
/***************************************************************************
 *   Copyright (C) 1997 to 2004 by Jonathan Duddington                     *
 *   email: jonsd@users.sourceforge.net                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write see:                           *
 *               <http://www.gnu.org/licenses/>.                           *
 ***************************************************************************/

/* Multi-threaded Write Mail/News */


#define REFS_MAX_LENGTH  998   /* max length of references: */
#define REFS_FOLDING     1000   /* fold line after this no of chars per line */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "kernel.h"
#include "os.h"
#include "wimp.h"
#include "werr.h"
#include "dbox.h"
#include "template.h"
#include "xferrecv.h"
#include "event.h"
#include "menu.h"
#include "flex.h"
#include "win.h"
#include "akbd.h"
#include "bbc.h"
#include "time.h"
#include "alarm.h"
#include "msgs.h"

#include "narc.h"
#include "hdrs.h"

#ifdef MemCheck
#include "MemCheck:Flex.h"
#endif

extern char *path_choices;
extern OPTIONS options;
extern int transport_opts;
extern TEXTR *textr_spellcheck;
extern ADDR_BOOK **addr_list;
extern BLIST boxlist;
extern BLIST mboxlist;
extern BOX box_table[N_BOXES];
extern dbox addr_insert_dbox;
extern char mbox_list[];
extern int mbox_selected;
extern int using_ramfs;

extern int text_monospaced;
extern FOLDREC list_fr[N_LISTS];
extern text_backg_colr;
extern char menu_get_number[8];
extern int dbox_menu_field;
extern char *status_sprites;

extern int lists_font_offset;
extern int scale_x;
extern char os_version_string[];
extern char *mailer_name;
extern CARDFILE_REC cardfile[N_CARDFILES];

char *err_newsgroups_no_dot = "Newsgroup name has no '.'  Is this OK?";

static char *menustr_editor = ">Save F3,Find F4,Addrbook F7,Speak F8,Spelling F9,Post ^P,Edit,PGP";
static char *menustr_edit = "Format ^F,Swap fonts ^F,Rot13 ^O,Quote ^Q,Unquote,Deleteline ^DEL,Wordwrap,External edit ^E";
static char *menustr_pgp = "Encrypt,Sign,Encrypt+Sign ^Y,Prevent encrypt,Prevent sign,Report,Keyring";
menu menu_pgp;
static char *msg_long_lines = "Message contains lines longer than 80 characters.  Use CTRL-F to reformat paragraphs";
static char *err_non_iso = "%s contains non ISO-8859-1 character codes, including %c (&%.2x)";


void text_reply_window(TEXTR *t, int type);

extern TEXTR *text_data_record[N_TEXT_DATA];

OPTIONS_MAILBOX *current_user;
OPTIONS_MAILBOX *bounce_user;
int current_user_num;
static char selected_sig[40];     /* sig to use */

wimp_menustr *wmenu_sigs;
static menu menu_sigs = 0;

static char fname_temp[32] = "<Pluto$Dir>.tmp.tmp1";
char fname_temp2[32] = "<Pluto$Dir>.tmp.tmp2";
static char fname_temp4[32] = "<Pluto$Dir>.tmp.tmp4";
char tmp_path[60];

static dbox dbox_bounce=0;
static CARD *bounce_card_ptr=NULL;
dbox dbox_reply;

static TEXTR *textr_menu;
menu menu_write;

char *refs_start = NULL;
int refs_length = 0;
static int own_address_flag=0;
static int destination_count=0;   /* number of addressees */
static int env_header_lines=0;    /* num of non addressee lines at start of env */
static int bcc_count=0;
int reply_supersede=0;
int  acks_held=0;       /* acks put in Hold directory */
int  acks_sent=0;       /* total acks produced */

static char fname_tags[32];
char sig_pgpkey[64];

static char *mime_version = "MIME-Version: 1.0\n";
char *content_encoding = "Content-Transfer-Encoding: ";
char *content_encoding_8bit = "8bit\n";
char *content_quoted_printable = "quoted-printable\n";
char *content_encoding_base64 = "BASE64\n";
static char *content_plain = "Content-Type: text/plain\n";
static char *content_plain_iso = "Content-Type: text/plain; charset=iso-8859-";
static char *string_subject = "Subject: ";


char *mime_style_names[] = {"UUE","MIME/R","MIME/PC"};
static char reply_reply_to_addr[60];
static char *menustr_mime_styles = "UUE,MIME/RISC OS,MIME/PC,Save";
static wimp_menustr *wmenu_mime_styles;
static int flag_organization;

static char reply_to_addr[80];
static char card_colours[] = {1,1,12,15};

static char check_char_tab[0xa0] = {
	'?','?','?','?','?','?','?','?','?',0,0,'?','?',0,'?','?',
	'?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'?',
	0,'W','w','?','?','Y','y','?','?','?','?','?','.','?','?','*',
	'\'','\'','<','>','"','"','"','-','-','-','?','?','?','?','i','l'
};



/**************************************************************************/
/*                       Menu of signatures                               */
/**************************************************************************/





/**************************************************************************/

typedef struct {
	wimp_msghdr hdr;
	char server_name[16];
	int  window[3];
	int  format;
	int  session;
	int  filetype;
	char filename[196];
} OLE1;


typedef struct {
	char type;
	char changed;
	int  task;
	int  your_ref;
	wimp_w window;
	void *handle;
	char *data;
} OLE_SESSION;

#define N_OLE_SESSIONS   10
OLE_SESSION OLE_session[N_OLE_SESSIONS];



void file_edit(char *fname)
/*************************/
/* Perform simple edit on a text file */
{
	wimp_msgstr msg;

	msg.data.dataopen.w = -1;
	msg.data.dataopen.i = -1;
	msg.data.dataopen.x = 0;
	msg.data.dataopen.y = 0;
	msg.data.dataopen.size = 0;
	msg.data.dataopen.type = 0xfff;
	strcpy(msg.data.dataopen.name,fname);

	msg.hdr.size = (strlen(fname) + 44 + 4) & ~3;
	msg.hdr.your_ref = 0;
	msg.hdr.action = wimp_MDATAOPEN;

	wimp_sendmessage(wimp_ESENDWANTACK,&msg,0);
}   /* end of file_edit */





int check_ramfs(void)
/******************/
{
	os_regset regs;

	using_ramfs = 0;

	regs.r[0] = 13;
	regs.r[1] = (int)"Mem:";
	regs.r[2] = 0;
	os_swi(0x29,&regs);   /* OS_FSControl, Check for presence of filing system */
	if(regs.r[2] != 0)
	{
		strcpy(tmp_path,"Mem::Sprites.$.Pluto");
		set_os_variable("Pluto$tmp",tmp_path);
		os_cli("cdir <Pluto$tmp>");
		using_ramfs = 1;
		return(1);
	}

#ifdef deleted
	/* problem with ram disc is that it can't expand when needed */
	regs.r[1] = (int)"RAM:";
	regs.r[2] = 0;
	os_swi(0x29,&regs);
	if(regs.r[2] != 0)
	{
		strcpy(tmp_path,"RAM::RamDisc0.$.Pluto");
		set_os_variable("Pluto$tmp",tmp_path);
		os_cli("cdir <Pluto$tmp>");
		return(1);
	}
#endif

	sprintf(tmp_path,"%stmp",pluto_path);
	set_os_variable("Pluto$tmp",tmp_path);
	return(0);
}   /* end of check_ramfs */





void check_ramfs2()
/*****************/
{
	check_ramfs();
	sprintf(fname_temp,"%s.tmp",tmp_path);
	sprintf(fname_temp2,"%s.tmp2",tmp_path);
}   /* end of check_ramfs2 */





int OLE_start(char *fname, int ftype, int type, int window, int attempt, void *handle)
/*****************************************************************************/
{
	char *p;
	char *server_name;
	char *server_run;
	int  session;
	OLE_SESSION *ole;
	OLE1 msg;
	int  length;
	char name[24];
	char buf[256];

	length = strlen(fname);
	if((length == 0) || (fname[length-1]=='.'))
		return(7);

	msg.hdr.action = message_OLEOpenSession;

	sprintf(name,"OLEServer$Type_%.3x",ftype);
	if(read_os_variable(name,buf,sizeof(buf)) != 0)
	{
		os_swi1(0x47b05+os_X,ftype);  /* OLE_SimulateSession */
		if(read_os_variable(name,buf,sizeof(buf)) != 0)
		{
			/* OLEsupport module is not present */
			file_edit(fname);
			return(6);
		}
	}

	server_name = strstr(buf,"-N ");
	if(server_name == NULL)
		return(1);
	server_name += 3;
	p = strchr(server_name,' ');
	if(p == NULL)
		return(2);
	*p++ = 0;

	if(attempt == 1)
	{
		server_run = strstr(p,"-R ");
		if(server_run != NULL)
			server_run += 3;

		wimp_starttask(server_run);
	}

	memset(&msg,0,sizeof(msg));

	for(session=0; session<N_OLE_SESSIONS; session++)
	{
		if(OLE_session[session].type == 0)
		{
			ole = &OLE_session[session];
			ole->type = type;
			ole->changed = 0;
			ole->task = 0;
			ole->window = window;
			ole->handle = handle;
			p = malloc(200);
			if(p == NULL)
				return(4);
			OLE_session[session].data = p;
			strcpy(p,fname);
			break;
		}
	}
	if(session == N_OLE_SESSIONS)
	{
		werr(0,"No more OLE sessions");
		return(3);
	}

	strcpy(msg.server_name,server_name);
	msg.format = attempt;
	msg.session = session;
	msg.filetype = ftype;
	strcpy(msg.filename,fname);

	msg.hdr.action = message_OLEOpenSession;
	msg.hdr.size = (61 + strlen(fname) + 3) & ~3;
	wimp_sendmessage(wimp_ESENDWANTACK,(wimp_msgstr *)&msg,0);   /* broadcast open_session */
	return(0);
}   /* end of OLE_start */



void OLE_free(int session)
/************************/
{
	OLE_SESSION *ole;

	ole = &OLE_session[session];

	ole->type = 0;
	if(ole->data != NULL)
		free(ole->data);
}   /* end of OLE_free */



void OLE_close_window(wimp_w window)
/**********************************/
/* Close the OLE session for the specified window, or
  for all windows (if window==NULL) */
{
	int  session;
	wimp_msgstr msg;
	OLE_SESSION *ole;

	for(session=0; session<N_OLE_SESSIONS; session++)
	{
		if(OLE_session[session].type != 0)
		{
			ole = &OLE_session[session];

			if((window != NULL) && (ole->window != window))
				continue;

			msg.hdr.size = 28;
			msg.hdr.your_ref = ole->your_ref;
			msg.hdr.action = message_OLECloseSession;
			msg.data.words[0] = 0;
			msg.data.words[1] = session;
			wimp_sendmessage(wimp_ESEND,&msg,ole->task);
		}
	}
}   /* end of OLE_close_window */




void OLE_started(wimp_eventdata *d,int ok)
/****************************************/
{
	OLE1 *msg;
	int  type;
	int  session;
	int  window;
	void *handle;

	msg = (OLE1 *)&d->msg;
	session = msg->session;

	if(!ok)
	{
		type = OLE_session[session].type;
		window = OLE_session[session].window;
		handle = OLE_session[session].handle;
		OLE_free(session);

		if(msg->format == 0)
			OLE_start(msg->filename,msg->filetype,type,window,1,handle);

		return;
	}

	OLE_session[session].task = msg->hdr.task;
	OLE_session[session].your_ref = msg->hdr.my_ref;
}   /* end of OLE_started */



void OLE_changed(wimp_eventdata *d)
/*********************************/
{
	int session;
	OLE_SESSION *ole;

	session = d->msg.data.words[1];
	if((session < 0) || (session >= N_OLE_SESSIONS))
		return;

	ole = &OLE_session[session];
	ole->changed = 1;

	switch(ole->type)
	{
	case 2:   /* edit Write Mail/News */
	case 4:   /* sorting/display types */
	case 5:   /* user dictionary */
		/* remember the new filename */
		if(d->msg.data.words[0] == 0)
			strcpy(ole->data,(char *)&d->msg.data.words[2]);
		break;

	case 1:   /* edit outgoing message queue */
	case 3:   /* view temp file */
	case 6:   /* PGP aliases */
	default:
		return;
	}
}   /* end of OLE_changed */



void OLE_edit_og_queue(OLE_SESSION *ole)
/**************************************/
{
	char *p;
	int  box;
	int  locked;
	int  status;
	int  action = 0x13;
	CARD *cptr;
	char *id=NULL;
	char *fname;
	int  user_num;

	if(ole->changed == 0)
		return;

	fname = ole->data;
	p = &fname[strlen(fname)];

	/* find leaf name from file name */
	while(--p > fname)
	{
		if(*p == '.')
		{
			id = p+1;
			break;
		}
	}
	if(id == NULL)
		return;

	cptr = posted_find_article(id);
	if(cptr != NULL)
	{
		box = cptr->date_box >> 26;
		status = cptr->status & STATUS_MASK;
		user_num = cptr->user & 0x1f;

		locked = 0;
		if((status == STATUS_LOCKED) || (status == STATUS_MARKED))
			locked = 0x200;

		if(cptr->status & STATUS_BIT_NEWS)
			action = 0x53;

		cardfile_remove(NULL,cptr,BOX_BIN);

		load_article(fname,0xfff,action+locked,box,id,user_num);
		posted_cache_delete(id);
		posted_make_list(7);
	}

}   /* end of OLE_edit_og_queue */



void fade_ext_edit(wimp_w w, int fade)
/************************************/
{
	wimp_set_icon_state(w,1,fade,wimp_INOSELECT);  /* un-fade Post button */
	wimp_set_icon_state(w,14,fade,wimp_INOSELECT);  /* un-fade Editor button */
}   /* end of fade_ext_edit */



int get_icon_state(wimp_w w, int icon)
/************************************/
{
	wimp_icon  icon_info;

	wimp_get_icon_info(w,icon,&icon_info);
	return(icon_info.flags);
}   /* end of get_icon_state */



void OLE_reply(OLE_SESSION *ole)
/******************************/
{
	int  i;
	TEXTR *t;
	int  length;
	char *fname;
	FILE *f;
	int  diff;

	t = (TEXTR *)ole->handle;
	fname = ole->data;

	if(t->dbox_card != 0)
	{
		fade_ext_edit(t->w_card,0);
		t->ole = 0;

		reopen_window(t->w_card,-1);   /* move to front */
		reopen_window(t->w_text,-1);
		reopen_window(t->w_attach,-1);

		/* Write window is no longer open */
		f = fopen_werr(fname,"r",NULL);
		if(f==NULL)
			return;

		length = get_filelength(fname);

		diff = length - t->text_body_end;
		if(diff > 0)
			move_down(t,t->text_body_end,diff);
		else if(diff < 0)
			move_up(t,t->text_body_end,-diff);

		for(i=0; i<length; i++)
		{
			t->text_base[i] = fgetc(f);
		}

		fclose(f);


		if(options.ext_edit == 0)
		{
			reply_set_ext_edit(t,1);   /* ext_edit option is no longer set */

			calc_line_tab(t);
			redraw_text_lines(t,0,-1);
			open_article(t,5);
		}
		else
		{
			calc_line_tab(t);
		}

	}

	if(memcmp_lc(fname,"<wimp$scrapdir>.pluto",21)==0)
		remove(fname);
	else if(strcmp(fname,ole->data)==0)
		remove(fname);  /* Zap returns full path name */
}   /* end of OLE_reply */




void OLE_close(wimp_eventdata *d)
/*******************************/
{
	int session;
	OLE_SESSION *ole;

	session = d->msg.data.words[1];
	if((session < 0) || (session >= N_OLE_SESSIONS))
		return;

	ole = &OLE_session[session];
	set_focus(ole->window);

	switch(ole->type)
	{
	case 1:   /* edit outgoing message queue */
		OLE_edit_og_queue(ole);
		break;

	case 2:
		OLE_reply(ole);
		break;

	case 3:   /* read temp file, delete after use */
		remove(ole->data);
		break;

	case 4:   /* edit display/sorting types */
		options_display_reload(ole->data);
		break;

	case 5:   /* edit user dictionary */
		spelldict_edit(ole->data);
		break;

	case 6:   /* edit PGP aliases */
		pgp_load_aliases();
		break;
	}
	OLE_free(session);
}   /* end of OLE_close */









char *cc_list_name(TEXTR *t, char *type)
/**************************************/
{
	static char buf[12];

	if(t->write_mail_tag==0)
		sprintf(buf,"%s_LIST",type);
	else
		sprintf(buf,"%s_LIST%d",type,t->write_mail_tag);
	return(buf);
}   /* end of cc_list_name */



int text_record_check(TEXTR *t)
/*****************************/
{
	int  i;

	if(t == NULL)
		return(-1);

	for(i=0; i<N_TEXT_DATA; i++)
	{
		if(text_data_record[i] == t)
			return(i);
	}
	return(-1);
}   /* end of text_record_check */




void text_data_free(TEXTR *t)
/***************************/
{
	int  i;
	char fname[128];

	if(t->text_type == X_VIEW)
		return;

	i = text_record_check(t);
	if(i < 0)
		return;

	text_data_record[i] = NULL;

	if(t->text_type > X_VIEW2)
	{
		sprintf(fname,"%s.Maillists.%s",path_choices,cc_list_name(t,"CC"));
		remove(fname);
	}

	if(t->art_out != NULL)
	{
		free(t->art_out);
	}
	if(t->text_base != NULL)
	{
		flex_free((flex_ptr)&t->text_base);
	}
	if(t->dbox_card != NULL)
	{
		dbox_dispose(&t->dbox_card);
		t->dbox_card = NULL;
	}
	if(t->w_text != NULL)
	{
		win_register_event_handler(t->w_text,NULL,NULL);
		wimp_delete_wind(t->w_text);
	}
	if(t->w_attach != NULL)
	{
		win_register_event_handler(t->w_attach,NULL,NULL);
		wimp_delete_wind(t->w_attach);
	}
	if(t->cardex != NULL)
	{
		free(t->cardex);
	}
	if(t->line_tab != NULL)
	{
		free(t->line_tab);
	}
	if(t->attach != NULL)
	{
		free(t->attach);
	}
	OLE_close_window(t->w_card);
	free(t);
}   /* end of text_data_free */



void text_data_free1(TEXTR* t)
/****************************/
{
	if(t->text_base!= NULL)
	{
		flex_free((flex_ptr)&t->text_base);
		t->text_base = NULL;
		t->text_buf_size = 0;
	}
}   /* end of text_data_free1 */





wimp_menustr *make_users_menu(int none)
/*************************************/
{
	int  i;
	int  mbox;
	char *first;
	char *p;
	int  count=0;
	static menu menu_users_names=0;
	char buf[24];

	if(menu_users_names != 0)
	{
		menu_dispose(&menu_users_names,0);
	}

	if(none)
	{
		first = "(none)";
		count=1;
	}
	else
		first = "";

	menu_users_names = menu_new("Users",first);


	for(i=0; (i<N_MAIL_BOX) && (i < mboxlist.n_entries); i++)
	{
		mbox = mbox_list[i];
		p = options.mailbox[mbox].email_addr;
		if((p[0] != 0) && (p[0] != '@'))
		{
			if(options.users_menu)
			{
				memcpy(buf,p,sizeof(buf));
				buf[sizeof(buf)-1] = 0;
				p = buf;
			}
			else
			{
				p = get_user_id(&options.mailbox[mbox]);
			}
		}
		else
		{
			p = "-";
		}

		count++;
		menu_extend(menu_users_names,p);
	}

	if(count==0)
	{
		menu_extend(menu_users_names,"(none)");
	}
	return((wimp_menustr *)menu_syshandle(menu_users_names));
}   /* end of make_users_menu */






char *get_user_id(OPTIONS_MAILBOX *user)
/**************************************/
{
	static char user_id[32];

	memcpy(user_id,user->email_addr,user->user_id_len);
	user_id[user->user_id_len]=0;
	return(user_id);
}   /* end of get_user_id */


char *get_user_id2(int user_num)
/******************************/
/* Returns use name part only of address */
{
	if(user_num <= 0)
		return("(none)");
	else
		return(get_user_id(&options.mailbox[user_num-1]));
}   /* end of get_user_id2 */


char *get_user_id3(int user_num)
/******************************/
/* Returns full email address */
{
	if(user_num <= 0)
		return("(none)");
	else
		return(options.mailbox[user_num-1].email_addr);
}   /* end of get_user_id3 */


char *get_user_domain(OPTIONS_MAILBOX *user)
/******************************************/
{
	return(&user->email_addr[user->user_id_len+1]);
}   /* end of get_domain_id */









char *reply_extract_email_addr(char *buf, int control)
/****************************************************/
/* control=bit 0, find the last @ in the string
           bit 1, buffer the output
           bit 2, include everything up to end off addr part (i.e. incl preceding name)
*/
{
	char *p;
	char *end;
	char *start;
	char *addr;
	char *at_sign;
	static char addr_buf[150];


	if(control & 1)
		p = strrchr(buf,'@');
	else
	{
		/* skip text in quotes */
		start = buf;
		while((*start != 0) && (strchr(",\n\t",*start)!= NULL))
			start++;

		if(*start == '"')
		{
			do {
				start++;
			} while ((*start != '"') && (*start != 0));
		}
		p = strchr(start,'@');
	}

	if(p == NULL)
		return(NULL);

	at_sign = p;

	if(control & 4)
		p = buf;
	else
	{
		while((p > buf) && (strchr("<) \t\n\",",p[-1])==NULL))
			p--;
	}

	if(control & 2)
	{
		/* buffer the output */
		strncpy(addr_buf,p,sizeof(addr_buf));
		addr_buf[sizeof(addr_buf)-1]=0;
		addr = addr_buf;
		at_sign = strrchr(addr,'@');
		if(at_sign == NULL)
			at_sign = addr;
	}
	else
	{
		addr = p;
	}

	if(control & 4)
		end = strpbrk(at_sign,"( \"'\t\n,");
	else
		end = strpbrk(at_sign,">( \"'\t\n,");

	if(end != NULL)
		*end = 0;

	return(addr);
}   /* end of reply_extract_email_addr */




int validate_email_addr(char *addr)
/******************************/
{
	int  i;
	int  len;
	char *at;
	static char *specials2 = ",;:\"\\()<>@[]";   /* without dot */

	addr = reply_extract_email_addr(addr,3);
	if(addr == NULL)
		return(-1);

	if((at = strchr(addr,'@')) == NULL)
	{
		/* no @ symbol */
		return(-1);
	}

#ifdef deleted
	/* deleted 11.07.02  Stefan Bellon */
	if(strchr(at,'.') == NULL)
	{
		/* no dot after the @ */
		return(-1);
	}
#endif

	/* look for disallowed characters */
	len = strlen(addr);
	for(i=0; i<len; i++)
	{
		if(strchr(specials2,addr[i]) != NULL)
		{
			if(&addr[i] != at)
				return(-1);
		}
	}

	/* dots are only allowed between words */
	if((addr[0] == '.') || (at[1] == '.') || (addr[len-1] == '.'))
	{
		return(-1);
	}

	if(strstr(addr,"..")!=NULL)
		return(-1);  /* .. not allowed */

	return(0);
}   /* end of validate_email_addr */




static int get_addr_param(char **ptr, char **param, int include_name)
/*******************************************************************/
/* Extract a string, up to comma or newline.
   return the address of the next parameter, or null if none */
{
	char *p;
	char *string;
	int  c;
	int  i;
	int  quoting;
	int  maillist = 0;
	int  ix;
	ADDR_BOOK *a;
	char *url;
	static char buf[128];

	string = *ptr;

	/* skip leading blanks */
	while(*string <= ' ')
	{
		if(*string == 0)
		{
			*param = NULL;   /* end of string, no more parameters */
			return(1);
		}
		string++;
	}

	p = strpbrk(string,",\n");
	if(p == NULL)
	{
		strcpy(buf,string);
	}
	else
	{
		quoting=0;
		p = string;
		i=0;
		for(i=0,p=string; i < sizeof(buf); p++)
		{
			c = *p;
			if(c == '"')
			{
				quoting ^= 1;
				continue;
			}

			if((c == 0) || (c == '\n') || ((c == ',') && (quoting==0)))
				break;

			buf[i++]=c;
		}
		buf[i] = 0;
	}

	if(validate_email_addr(buf) < 0)
	{
		/* not an email address, look up the address book */
		ix = addr_list_lookup_menu(buf);

		if(ix < 0)
			maillist = 2;
		else
		{
			a = addr_list[ix];
			if(a->data[a->offset]==0)
			{
				/* no URL, must be a distribution list that's in the address book */
				maillist = 2;
			}
			else
			{
				url = &a->data[a->offset];
				if(strchr(url,'@')==NULL)
				{
					/* not a full email address, perhaps a distribution list */
					include_name = 0;
					maillist = 2;
				}
				else
				{
					/* look to see if it's a mailing list that we're running */
					for(i=0; i<N_MAIL_BOX; i++)
					{
						if((strcmp(options.mailbox[i].email_addr,url)==0) &&
								(options.mailbox[i].mail_list_server != 0))
						{
							include_name = 0;
							maillist = 2;
							break;
						}
					}
				}

				if((include_name) && (a->data[0]!=0))
					sprintf(buf,"%s <%s>",a->data,url);
				else
				{
					strcpy(buf,url);

					if(maillist)
					{
						if((url = strchr(buf,'@')) != NULL)
						{
							*url = 0;  /* only keep user name, not domain for mailing list */
						}
					}
				}

#ifdef deleted
				if((include_name) && (a->data[0]!=0) && (a->data[a->alias] !=0))
					sprintf(buf,"%s <%s>",a->data,url);
				else
					strcpy(buf,url);
#endif
			}
		}
	}
	*param = buf;

	if((p == NULL) || (*p != ','))
		return(1 + maillist);   /* no more parameters */

	*ptr = ++p;   /* skip the comma */
	return(0 + maillist);
}   /* end of get_addr_param */







void f_fold(FILE *f,char *string, int posn, int iso)
/**************************************************/
{
	char *p;
	char *last_space = string;
	char *iso_string = NULL;
	int iso_string_len;

	if(memcmp(string,"=?",2)==0)
	{
		p = strchr(&string[3],'?');
		if((p != NULL) && ((p-string) < 14))
		{
			iso_string = string;
			iso_string_len = p-string + 3;
		}
	}
	else
	{
		/* don't fold subject string unless it's iso encoded */
		fprintf(f,"%s\n",string);
		return;
	}


	p = string;
	for(;;)
	{
		if(*p == 0)
		{
			fprintf(f,"%s\n",string);
			return;
		}
		if(*p == ' ')
			last_space = p;

		if(iso_string && (*p == '_'))
			last_space = p;

		p++;

		if((posn++ >= 79) && ((last_space - string) > 5))
		{
			fwrite(string,1,last_space-string,f);

			if(*last_space == '_')
			{
				fprintf(f,"?=\n ");
				fwrite(iso_string,1,iso_string_len,f);
				posn = iso_string_len + 1;
			}
			else
			{
				fputc('\n',f);
				posn = 1;
			}
			p = string = last_space;
		}
	}
}   /* end of f_fold */





char *iso_encode_string(char *string, int control, char *field, TEXTR *t)
/***********************************************************************/
/* control:  bit 0   1=News message
             bit 1   1=An address
             bit 2   1=Allow "edit" option, return NULL
*/
{
	char *p;
	int  c;
	int  c2;
	int  c3;
	int top_bit = 0;
	int character;
	int reported=0;
	int charset=1;
	int action;
	static char quote_buf[128+24];

	if((t!=NULL) && (t->charset > 1))
		charset = t->charset;

	p = string;
	while((c = *p++) != 0)
	{
		if((c < 0xa0) && ((c2 = check_char_tab[c]) > 0))
		{
			if(reported==0)
			{
				c3 = c;
				if(c3 < ' ') c3 = ' ';
				sprintf(quote_buf,err_non_iso,field,c3,c);

				if(control & 4)
					action = query3(quote_buf,"Auto-Replace","Continue","Edit");
				else
					action = query2(quote_buf,"Replace","Continue");

				switch(action)
				{
				case 0:
					reported = 1;
					break;
				case 1:
					reported=2;
					break;
				case 2:
					return(NULL);
				}
			}

			if(reported==2)
			{
				c = c2;
				p[-1] = c;
			}
		}

		if(c >= 127)
		{
			top_bit = 1;
			character = c;
		}
	}

	if(top_bit)
	{
		if(charset == 100)
		{
			/* unknown character set, don't encode */
		}
		else if(control & 1)
			werr(0,"Should not use character '%c' in a News header",character);
		else
		{
			if(charset == 101)
				sprintf(quote_buf,"=?koi8-r?q?");
			else
			{
				if(charset > 20)
					charset = 1;
				sprintf(quote_buf,"=?iso-8859-%d?q?",charset);
			}


			p = &quote_buf[strlen(quote_buf)];
			while((c = *string++) != 0)
			{
				if(c == ' ')
					c = '_';

				if((strchr("=?",c)!=NULL) || (c <= ' ') || (c >= 127) || (strchr(",.;:()<>[]@\\",c) != NULL))
				{
					sprintf(p,"=%.2X",c);
					p += 3;
				}
				else
				{
					*p++ = c;
				}
			}
			sprintf(p,"?=");
			return(quote_buf);
		}
	}
	return(string);
}   /* end of iso_encode_string */




static void reply_content_type(TEXTR *t, FILE *f)
/***********************************************/
{
	int  charset=1;

	if(t==NULL)
		return;

	if((t->charset > 1) && (t->charset < 100))
		charset = t->charset;

	if(t->boundary_string_len > 0)
	{
		fprintf(f,"This is a MIME encapsulated message.\n");

		if(t->art_out->encoding >= 0)
			fprintf(f,"\n--%s\n",t->boundary_string);
	}

	switch(t->art_out->encoding)
	{
	case 0:
		fprintf(f,content_plain);
		break;

	case 1:
		fprintf(f,"%s%d\n%s%s",content_plain_iso,charset,content_encoding,content_quoted_printable);
		break;

	case 2:
		fprintf(f,"%s%d\n%s%s",content_plain_iso,charset,content_encoding,content_encoding_8bit);
		break;
	}
}   /* end of reply_content_type */




static void reply_multipart_header(TEXTR *t, FILE *f, int type)
/*************************************************************/
{
	if(t==NULL)
		return;

	if(t->attachments==0)
		t->boundary_string_len = 0;

	if(t->boundary_string_len > 0)
	{
		fprintf(f,"Content-Type: MULTIPART/MIXED; BOUNDARY=\"%s\"\n",t->boundary_string);
	}
	else
	{
		if(type == X_MAIL)
		{
			reply_content_type(t,f);
		}
	}
}   /* end of reply_multipart_header */







char *reply_addr_chain = NULL;
char **reply_addr_chain_next = NULL;


static int reply_add_addr(int type, char *addr, int spam_check)
/*************************************************************/
/* Add to the list of addressees */
{
	int  length;
	char *ptr;
	char **ptr2;
	int  i;
	int spam=0;
	char *addr2;
	NEWSG *ng;
	char *p;
	char buf[180];


	length = strlen(addr);
	if(length == 0)
		return(1);

	if(((p = strstr(addr,"NS"))!=NULL) && !isupper(p[-1]) && !isupper(p[2]))
	{
		spam=1;
	}
	else
	{
		for(i=0; i<(length-4); i++)
		{
			if((memcmp_lc(&addr[i],"spam",4)==0) || (memcmp_lc(&addr[i],"remove",6)==0) ||
					(memcmp_lc(&addr[i],".invalid",8)==0))
			{
				spam=1;
				break;
			}
		}
	}

	if(spam_check && spam && (addr_lookup_url(reply_extract_email_addr(addr,3))==NULL))
	{
		/* don't query this if the address is in the address book */
		sprintf(buf,"Is this a correct address? %s",addr);
		if(query(buf,NULL)==0)
			return(1);
	}

	/* check for a read-only mailing list */
	addr2 = reply_extract_email_addr(addr,3);
	sprintf(buf,"mail.%s",addr2);
	ng = newsg_lookup2(buf);
	if(ng != NULL)
	{
		if(ng->ng_flags & NG_READ_ONLY)
		{
			sprintf(buf,"Mailing list  %s  is marked as Read Only",addr2);
			if(query(buf,NULL)==0)
				return(1);
		}
	}

	ptr = malloc(length+8);
	if(ptr == NULL)
		return(1);

	ptr2 = (char **)ptr;
	ptr2[0] = NULL;
	ptr[4] = type;
	strcpy(&ptr[5],addr);

	if(type <= 1)
	{
		strncpy(reply_to_addr,addr,sizeof(reply_to_addr));
		reply_to_addr[sizeof(reply_to_addr)-1] = 0;
	}

	*reply_addr_chain_next = ptr;
	reply_addr_chain_next = ptr2;
	return(0);
}   /* end of reply_add_addr */



void reply_addr_free_chain()
/**************************/
{
	char *ptr;
	char **ptr2;

	ptr = reply_addr_chain;
	reply_addr_chain = NULL;
	reply_addr_chain_next = &reply_addr_chain;

	while(ptr != NULL)
	{
		ptr2 = (char **)ptr;
		ptr = ptr2[0];
		free(ptr2);
	}
}   /* reply_addr_free_chain */



static void reply_addr_write(int type, FILE *f, FILE *f2, FILE *f_pgp, TEXTR *t)
/******************************************************************************/
/* Write out the addresses of the specified type */
{
	char *ptr;
	char **ptr2;
	int  i;
	int  count=0;
	int  type1;
	int  flags;
	int  reply_to_count=0;
	char *p;
	char *p_alias;
	char *p_angle;
	char *p_comma;
	char buf[128+24];
	char buf2[128+26];

	static char *name[] = {"To","To","Cc","Bcc","Reply-to"};
	static char flags_data[] = {3,1,3,2,1};

	ptr = reply_addr_chain;

	for(ptr=reply_addr_chain; ptr != NULL; ptr = ptr2[0])
	{
		ptr2 = (char **)ptr;

		flags = flags_data[ptr[4]];
		type1 = ptr[4];
		if(type1 == 0)
			type1 = 1;

		if(type1 != type)
			continue;

		p = &ptr[5];

		if(type==4)
		{
			if(reply_to_count>0)
				continue;
			reply_to_count++;

			if(f==NULL)
				strncpy0(reply_reply_to_addr,p,sizeof(reply_reply_to_addr));
		}

		count++;
		if((f != NULL) && (flags & 1))
		{
			/* include in email header */
			p_angle = strrchr(p,'<');
			if(p_angle == NULL) p_angle = p;

			while((p_angle > p) && (isspace(p_angle[-1])))
				p_angle--;

			if(p_angle > p)
			{
				/* there is a comment part to the address */
				memcpy(buf,p,p_angle-p);
				buf[p_angle-p] = 0;

				strcpy(buf2,iso_encode_string(buf,2,"Address",t));
				p_comma = strpbrk(buf2,",.;:()<>[]@\\");

				if((p_comma != NULL) && (buf2[0] != '"'))
				{
					/* enclose in double quotes */
					sprintf(buf,"\"%s\"",buf2);
				}
				else
				{
					strcpy(buf,buf2);
				}
			}
			else
			{
				buf[0] = 0;
			}
			strcat(buf,p_angle);

			if(flags & 1)
			{
				/* write to message header */
				if(count==1)
				{
					fprintf(f,"\n%s: %s",name[type],buf);
				}
				else
				{
					fprintf(f,",\n\t%s",buf);
				}
			}
		}



		if((f2 != NULL) && (flags & 2))
		{
			/* include in envelope */
			strcpy(buf,&ptr[5]);
			p = reply_extract_email_addr(buf,1);

			if(p != NULL)
			{
				if(f_pgp)
				{
					/* look up in PGP alias list */
					p_alias = pgp_lookup_alias(p);
					if(p_alias == NULL)
						p_alias = p;
					fprintf(f_pgp,"%s\n",p_alias);
				}

				/* is this one of our own addresses, which is a maillist server ? */
				for(i=0; i<N_MAIL_BOX ; i++)
				{
					if(strcmp_lc(p,options.mailbox[i].email_addr)==0)
					{
						if(options.local_mail || (options.mailbox[i].mail_list_server > 0))
						{
							own_address_flag = 1;
							p = NULL;
							break;
						}
					}
				}
			}

			if(p != NULL)
			{
				if((transport_opts & TOPS_MAIL_ANT) || (options.mail_transport == X_FREESMTP))
				{
					fprintf(f2,"RCPT TO:<%s>\n",p);
				}
				else
				{
					fprintf(f2,"%s\n",p);
				}
				destination_count++;
			}
		}
	}
}   /* end of reply_addr_write */





static void add_tag(FILE *f_out, int position)
/********************************************/
{
	FILE *f;
	char *p;
	int  count=0;
	char buf[256];

	sprintf(buf,"%s.%s",path_choices,fname_tags);
	f = fopen_werr(buf,"r","tags ");

	buf[0] = 0;

	if(f!=NULL)
	{
		/* count number of tags */
		while(!feof(f))
		{
			if(fgets(buf,sizeof(buf)-1,f) == NULL)
				break;
			if(buf[0] != '\n')
				count++;
		}
		rewind(f);

		if(count == 0)
		{
			fclose(f);
			return;
		}

		srand((int)clock());  /* seed random number generator */
		count = rand() % count;

		while(count >= 0)
		{
			if(fgets(buf,sizeof(buf)-1,f) == NULL)
			{
				fclose(f);
				return;
			}
			if(buf[0] != '\n')
				count--;
		}
		fclose(f);
	}

	/* replace |M by newline in tags */
	p = buf;
	while((p = strstr(p,"|M")) != NULL)
	{
		p[0] = ' ';  /* trailing space, but saves having to move following chars up */
		p[1] = '\n';
	}
	switch(position)
	{
	case 1:
		fprintf(f_out,"* %s",buf);
		break;
	case 2:
		fprintf(f_out,"%s\n",buf);
		break;
	case 3:
		fprintf(f_out,"\n%s",buf);
		break;
	case 4:
		buf[strlen(buf)-1]=0;  /* delete NL at end of line */
		fprintf(f_out,"%s",buf);
		break;
	}
	return;
}   /* end of add_tag */






static int add_sig(FILE *f, TEXTR *t, int type, char *sig, int tag)
/*****************************************************************/
/* type = X_MAIL or X_NEWS
          bit 4=1   use extra header lines
          bit 5=1   use quoted printable encoding for signature
   tag= tag position(1,2,3)  0 no tag,
              -1 inhibit sig separator */
{
	int  i;
	FILE *f_sig;
	int  length;
	int  len;
	int  nl_count;
	int  c;
	char *p;
	char *sig_buf;
	int  separator_flag = 0;
	int  top_bit_flag = 0;
	int  text_type;
	int  encoding;
	char buf[180];

	if(tag == 1)
	{
		add_tag(f,tag);   /* before sig sep. */
	}

	if(sig[0] == 0)
		return(0);   /* no sig. selected */

	sprintf(buf,"%s.Signatures.%s",path_choices,sig);
	f_sig = fopen(buf,"r");
	if(f_sig == NULL)
	{
		return(0);
	}

	length = get_filelength(buf);
	if(length == 0)
	{
		fclose(f_sig);
		return(0);
	}

	text_type = type & 0xf;
	encoding = 0;
	if(type & 0x20)
	{
		encoding = 1;
	}
	if((t != NULL) && (t->art_out->encoding == 1))
	{
		encoding = 1;
	}

	if(type & 0x10)
	{
		/* add extra header lines */
		flag_organization = 0;
		strcpy(fname_tags,"Tags");   /* default tags file */
		sig_pgpkey[0]=0;

		while(!feof(f_sig))
		{
			if(fgets(buf,sizeof(buf),f_sig) != NULL)
			{
				if(buf[0]=='$')
				{
					p = &buf[1];

					if(*p == 'm')
					{
						if(text_type != X_MAIL)
							continue;
						p++;
					}
					else if(*p == 'n')
					{
						if(text_type != X_NEWS)
							continue;
						p++;
					}

					if(isspace(*p)) p++;

					if((memcmp_lc2(p,"Organization:",13)==0) || (memcmp_lc2(p,"Organisation:",13)==0))
						flag_organization = 1;

					if(memcmp(p,"Bcc:",4)==0)
					{
						if(text_type == X_MAIL)
							reply_add_addr(3,&p[5],1);
					}
					else if(memcmp(p,"tagfile",7)==0)
					{
						p+=7;
						while(isspace(*p)) p++;
						i=0;
						while((*p > ' ') && (i < (sizeof(fname_tags)-1) ))
							fname_tags[i++] = *p++;
						fname_tags[i]=0;
					}
					else if(memcmp(p,"pgpkey",6)==0)
					{
						p+=6;
						while(isspace(*p)) p++;
						i=0;
						while((*p >= ' ') && (i < (sizeof(sig_pgpkey)-1) ))
							sig_pgpkey[i++] = *p++;
						sig_pgpkey[i]=0;
					}
					else
						fwrite(p,1,strlen(p),f);
				}
				else
				{
					break;
				}
			}
		}
		fclose(f_sig);
		return(0);
	}

	sig_buf = malloc(length);
	if(sig_buf == NULL)
	{
		fclose(f_sig);
		return(0);
	}

	nl_count = 0;
	length = 0;
	while(!feof(f_sig))
	{
		if(fgets(buf,sizeof(buf),f_sig)!=NULL)
		{
			if(buf[0]=='$')
			{
				if((memcmp(&buf[1],"tag",3)!=0) || (!isspace(buf[4])))
					continue;    /* extra header line, unless $tag (insert Tag) */
			}

			nl_count++;

			if(memcmp(buf,"-- \n",4)==0)
				separator_flag = 1;

			len = strlen(buf);

#ifdef deleted
			if((text_type == X_MAIL) && (options.mail_8bit==0))
			{
				/* check for top bit set characters */
				for(i=0; i<len; i++)
				{
					if(buf[i] > 126)
					{
						buf[i] = '#';
						top_bit_flag = 1;
					}
				}
			}
#endif

			memcpy(&sig_buf[length],buf,len);
			length += len;
		}
	}
	fclose(f_sig);


	if(top_bit_flag)
	{
		if(query2("Signature contains top-bit-set characters","Change","Post"))
		{
			free(sig_buf);
			return(1);
		}
	}
	else if((text_type == X_NEWS) && (nl_count > 7))
	{
		if(query2("Too many lines in sig.","Change","Post"))
		{
			free(sig_buf);
			return(1);
		}
	}
	else if((text_type == X_NEWS) && (length > 330))
	{
		if(query2("Sig. is too long","Change","Post"))
		{
			free(sig_buf);
			return(1);
		}
	}

	if(tag == -1)
	{
		/* inhibit sig separator */
		fputc('\n',f);
	}
	else if((separator_flag == 0) && (length > 0))
	{
		if(encoding == 1)
			fprintf(f,"--=20\n");
		else
			fprintf(f,"-- \n");    /* sig. seperator */
	}

	if(tag==2)
	{
		add_tag(f,tag);   /* after sig seperater */
	}

	if(length > 0)
	{
		for(i=0; i<length; i++)
		{
			c = sig_buf[i];

			if((c == '$') && (memcmp(&sig_buf[i+1],"tag",3)==0))
			{
				/* insert Tag at this point */
				i+=4;
				add_tag(f,4);
				tag=0;
				c = sig_buf[i];

				if(i >= length)
					c = '\n';
			}

			if((encoding == 1) && ((c >= 127) || (c == '=')))
				fprintf(f,"=%.2X",c);
			else
				fputc(c,f);
		}

		if(sig_buf[length-1] != '\n')
			fputc('\n',f);
	}

	free(sig_buf);

	if(tag == 3)
	{
		add_tag(f,tag);
	}
	return(0);
}   /* end of add_sig */





char *make_legal_fname(char *user_id)
/***********************************/
/* Replace illegal characters in file name */
{
	int  i;
	int  c;
	static char name[64];

	for(i=0; i<(sizeof(name)-1); i++)
	{
		c = user_id[i];
		if(c == 0)
			break;

		if(c == ' ')
			c = '_';
		else if(strchr(" $&%@\\^:.,#*\"|",c) != NULL)
			c = '/';
		name[i] = c;
	}
	name[i]=0;
	return(name);
}   /* end of make_legal_fname */








void reply_show_user_id(TEXTR *t)
/*******************************/
{
	char *p;

	if(t->selected_user->flags & 4)
		p = t->selected_user->email_addr;
	else
		p = get_user_id(t->selected_user);
	dbox_setfield(t->dbox_card,6,p);

	dbox_setfield(t->dbox_card,0,t->selected_sig);
}   /* end of reply_show_user_id */




void user_select(TEXTR *t, int user_no, int temp)
/***********************************************/
{
	OPTIONS_MAILBOX *user2;
	char sig[32];

	user2 = &options.mailbox[user_no];
	strcpy(sig,make_legal_fname(user2->signature));
	sig[15] = 0;

	if(temp==0)
	{
		current_user = user2;
		current_user_num = user_no;
		strcpy(selected_sig,sig);
	}

	if(t != NULL)
	{
		t->selected_user = user2;
		t->selected_user_num = user_no;
		strcpy(t->selected_sig,sig);

		if(t->dbox_card != NULL)
		{
			reply_show_user_id(t);
		}
	}
}   /* end of user_select */






static int reply_mail_list(char *name, int type)
/**********************************************/
/* Write out destination information from a distribution list .
   type: 1,2,3  assume To, Cc, Bcc  don't need this is dist list
         0      need !To: etc in dist list
         0x10   as 0, but don't add To addresses to envelope file

   f can be NULL in order to only produce an envelope file (for Bounce)
*/
{
	char *p;
	FILE *f_list;
	int  line=0;
	int  count=0;
	int  errors=0;
	int  ix;
	ADDR_BOOK *a;
	int  suppress_to_addresses;
	char buf[256];
	char bad_address[128];

	suppress_to_addresses = type & 0x10;
	if((type & 0xf)==0)
		type = -1;

	sprintf(buf,"%s.Maillists.%s",path_choices,make_legal_fname(name));
	f_list = fopen(buf,"r");
	if(f_list == NULL)
		return(1);

	while(!feof(f_list))
	{
		if(fgets(buf,sizeof(buf),f_list) == NULL)
			break;

		line++;
		buf[strlen(buf)-1] = 0;  /* remove NL from the end of the line */

		if(strchr("|#;",buf[0])!=NULL)
		{
			/* a comment, ignore */
			continue;
		}

		p = buf;
		while(isspace(*p++));
		if(*p == 0)
			continue;   /* blank line */


		if(buf[0] == '!')
		{
			count = 0;

			if(memcmp_lc(buf,"!cc:",3) == 0)
			{
				type = 2;
			}
			else if(memcmp_lc(buf,"!bcc:",4) == 0)
			{
				type = 3;
			}
			else if(memcmp_lc(buf,"!to:",3) == 0)
			{
				if(suppress_to_addresses)
					type = 1;
				else
					type = 0;
			}
			else if(memcmp_lc(buf,"!reply-to:",9) == 0)
			{
				type = 4;
			}
			else
			{
				werr(0,"Error in distribution list at line %d",line);
				fclose(f_list);
				return(2);
			}
		}
		else
		{
			if(type < 0)
			{
				werr(0,"Error in distribution list, no command line before line %d",line);
				fclose(f_list);
				return(3);
			}

			/* just take the email address, up to a blank */
			if((type==2) || (type==3))
			{
				p = reply_extract_email_addr(buf,5);
				if(p == NULL)
					p = buf;

				ix = addr_list_lookup_menu(buf);
				if(ix > 0)
				{
					a = addr_list[ix];
					p = &a->data[a->offset];
				}

				if(strchr(p,'@')==NULL)
				{
					strcpy(bad_address,p);
					errors++;
				}
			}
			else
			{
				/* strip trailing blanks */
				p = &buf[strlen(buf)];
				while(--p > buf)
				{
					if(*p > ' ')
					{
						p[1] = 0;
						break;
					}
				}
				p = buf;
			}
			reply_add_addr(type,p,0);
		}
	}

	fclose(f_list);

	if(errors)
	{
		werr(0,"Distribution list '%s' contains %d bad addresses. '%s'",name,errors,bad_address);
	}
	return(0);
}   /* end of reply_mail_list */







int reply_destinations(char *dest, OPTIONS_MAILBOX *user, int control)
/*******************************************************************/
/* Control: bit 0  report unrecogniesed address
            bit 4  suppress To: addresses from distribution list */
{
	FILE *f2;
	char *p;
	char *param;
	int  i;
	int  j;

	reply_reply_to_addr[0] = 0;

	/* envelope file */
	check_ramfs2();   /* set tmp path */
	f2 = fopen_werr(fname_temp2,"w",NULL);
	if(f2==NULL) return(1);


	env_header_lines = 1;
	if(options.mail_transport == X_ANT)
	{
		fprintf(f2,"MAIL FROM:<%s>\n",user->email_addr);
	}
	else
	{
		if(options.mail_transport == X_FREESMTP)
		{
			fprintf(f2,"GATE VIA:localhost\nMAIL FROM:<%s>\n",user->email_addr);
		}
		else
		{
			if(transport_opts & TOPS_MAIL_ENV_DOMAIN)
			{
				fprintf(f2,"%s",get_user_domain(user));
				env_header_lines++;
			}

			fprintf(f2,"\n%s\n",user->email_addr);
		}
	}


	/* extract email address from destination name */

	reply_addr_chain = NULL;
	reply_addr_chain_next = &reply_addr_chain;

	p = dest;
	do {
		i = get_addr_param(&p,&param,0);
		if(i & 2)
		{
			if((j = reply_mail_list(param,control & 0x10)) != 0)
			{
				fclose(f2);
				if(j == 1)
				{
					if(control & 1)
						werr(0,"Name in 'To' field is not recognised (%s)",param);
					return(3);
				}
				return(2);
			}
		}
		else
		{
			if(param == NULL)
				break;

			reply_add_addr(0,param,0);   /* envelope file */
		}

	} while((i & 1) == 0);

	/* write out addresses */
	for(i=1; i<=4; i++)
	{
		reply_addr_write(i,NULL,f2,NULL,NULL);
	}
	reply_addr_free_chain();

	fclose(f2);
	return(0);
}   /* end of reply_destinations */




char *user_full_name(OPTIONS_MAILBOX *user)
/*****************************************/
/* Get user's proper name, adding quotes if it contains a comma */
{
	static char string[sizeof(user->full_name)+2];

	if((strpbrk(user->full_name,",';:()<>[]@\\") != NULL) && (user->full_name[0] != 0))
	{
		sprintf(string,"\"%s\"",user->full_name);
		return(string);
	}

	return(user->full_name);
}   /* user_full_name */




void reply_add_to_field(dbox d,int field,char *name)
/*********************************************/
{
	int  len;
	char buf[350];

	/* append the address to the specified dbox field */
	dbox_getfield(d,field,buf,sizeof(buf)-1);
	if(buf[0] != 0)
	{
		len = strlen(buf);
		if(buf[len-1] != ',')
			strncat(buf,",",sizeof(buf)-1);
	}

	if(strchr(name,',')!=0)
		sprintf(buf,"%s\"%s\"",buf,name);
	else
		strncat(buf,name,sizeof(buf)-1);

	len = dbox_widthfield(d,field);
	if(strlen(buf) > len)
	{
		werr(0,"Field is full");
	}
	else
	{
		dbox_setfield(d,field,buf);
	}
}   /* end of reply_add_to_field */




int copy_env_file(char *from, char *to, int crlf, int start, int max)
/*******************************************************************/
/* Copy addressees */
{
	int  line;
	int  len;
	int  end;
	FILE *f_env;
	FILE *f_from;

	char buf[128];

	f_from = fopen_werr(from,"r",NULL);
	if(f_from==NULL)
		return(1);

	f_env = fopen_werr(to,"w",NULL);
	if(f_env==NULL)
	{
		fclose(f_from);
		return(2);
	}

	start += env_header_lines;
	end = start+max;

	line = 0;
	while(!feof(f_from))
	{
		if(fgets(buf,sizeof(buf),f_from)==NULL)
			break;
		line++;

		if(line > end)
			break;

		if((line <= env_header_lines) || (line > start))
		{

			if(crlf)
			{
				len = strlen(buf);
				buf[len-1] = '\r';
				fprintf(f_env,"%s\n",buf);  /* end line with CR LF */
			}
			else
			{
				fprintf(f_env,"%s",buf);
			}
		}
	}

	if(crlf==2)
	{
		fprintf(f_env,"DATA\r\n");
	}


	fclose(f_env);
	fclose(f_from);
	return(0);
}   /* end of copy_env_file */




int bounce_article(char **anchor, int start, int length, int user_number, int type, int log_box)
/**********************************************************************************************/
/* user = user number + 1 */
{
	FILE *f;
	int  c;
	int  i;
	int  ix;
	char *p;
	char *p2;
	int  skip;
	int  encoding=0;
	int  body_start;
	int  reply_to_flag=0;
	int  sig_type;
	FILE *f2;
	int  dest_count=0;
	int  max_addr=999;
	int  start_addr=0;
	char fname[150];
	char fname2[150];
	char fname_out[12];
	char fname_out2[12];

	static char *ignore_hdrs[] = {
		"return-receipt-to:",
		"x-confirm-reading-to:",
		"x-pop3-mailbox:",
		"envelope-to:",
		"x-envelope-to:",
		"delivery-date:",
		"return-path:",
		"status:",
		"x-status:",
		"x-mime-autoconverted:",
		"precedence:",
		"lines:",
		"content-length:",
		"x-uidl:",
		NULL
	};

	strcpy(fname_out,get_message_id(0,type));
	strcpy(fname_out2,fname_out);

	/* count addressees and split if there are too many */
	if(options.limit_recipients > 0)
		max_addr = options.limit_recipients;

	if((f2 = fopen_werr(fname_temp2,"r",NULL)) == NULL)
		return(-1);

	while((c = fgetc(f2)) != EOF)
	{
		if(c == '\n')
			dest_count++;
	}
	fclose(f2);
	dest_count -= env_header_lines;

	while(dest_count > 0)
	{
		/* create mail message */
		sprintf(fname,"%s.%s",options.mail_out,fname_out2);
		sprintf(fname2,"%s.%s",options.mail_envs,fname_out2);



		if(transport_opts & TOPS_MAIL_CRLF)
		{
			if(copy_env_file(fname_temp2,fname,2,start_addr,max_addr) != 0)
				return(1);

			if((f = fopen_werr(fname,"a",NULL))==NULL)
				return(-1);
		}
		else
		{
			if(copy_env_file(fname_temp2,fname2,0,start_addr,max_addr) != 0)
				return(1);

			if((f = fopen_werr(fname,"w",NULL))==NULL)
				return(-1);
		}

		p = *anchor;
		p += start;

		for(i=0; i<length; i++)
		{
			skip=0;
			if((i==0) || ((i > 0) && (p[i-1] == '\n')))
			{
				if(p[i]=='\n')
				{
					/* end of header */
					if((user_number >= 0) && (options.mailbox[user_number].mail_list_server))
					{
						if((reply_to_flag==0) && (reply_reply_to_addr[0] != 0))
							fprintf(f,"Reply-To: %s\n",reply_reply_to_addr);  /* !Reply-To: entry in dist.list */

						fprintf(f,"Precedence: bulk\n");

						add_sig(f,NULL,0x10+X_MAIL,options.mailbox[user_number].signature,0);   /* extra header lines */
						fputc('\n',f);
					}
					else
					{
						fprintf(f,"\nReSent-From: %s <%s>\n",user_full_name(bounce_user),bounce_user->email_addr);
						if(reply_to_addr[0] != 0)
							fprintf(f,"ReSent-To: %s\n",reply_to_addr);
						fputc('\n',f);
					}
					i++;
					break;
				}


				/* omit certain lines in the header */
				if(memcmp_lc(&p[i],"content-transfer-encoding: quoted-printable",43)==0)
					encoding = 1;

				if(memcmp_lc(&p[i],"reply-to:",9) == 0)
					reply_to_flag = 1;

				for(ix=0; (p2=ignore_hdrs[ix])!=NULL; ix++)
				{
					if(memcmp_lc(&p[i],p2,strlen(p2))==0)
					{
						/* skip this line */
						for(; i<length; i++)
						{
							if((p[i] == '\n') && (p[i+1] != ' ') && (p[i+1] != '\t'))
							{
								skip=1;
								break;
							}
						}
						break;
					}
				}
			}
			if(skip==0)
				fputc(p[i],f);
		}
		body_start = i;

		while(i<length)
		{
			fputc(p[i++],f);
		}

		/* is there a sig to be added ? */
		if((user_number >= 0) && (options.mailbox[user_number].mail_list_server))
		{
			i = text_find_sig(&p[body_start],length-body_start);
			if(i != 0)
				i = -1;   /* inhibit sig separator */

			if(encoding == 1)
				sig_type = X_MAIL+0x20;   /* use  --=20  separator */
			else
				sig_type = X_MAIL;

			add_sig(f,NULL,sig_type,options.mailbox[user_number].signature,i);
		}

		if(transport_opts & TOPS_MAIL_DOT)
		{
			fprintf(f,"\r\n.\r\n");
		}
		fclose(f);


		dest_count -= max_addr;   /* continue with more addressees ? */
		start_addr += max_addr;
		strcpy(fname_out2,get_message_id(0,type)); /* change filename */
	}


	if((log_box >= 0) && (log_box < BOX_BIN))
		load_article(fname,0xfff,0x13,log_box,fname_out,user_number+1);

	postedlist_reopen();
	return(0);
}   /* end of bounce_article */




int bounce_article2(TEXTR *t, CARD *cptr, int user_number, int type, int log)
/***************************************************************************/
{
	int log_box = -1;
	CARD_EXPANDED card_ex;

	unpack_card(cptr,&card_ex);

	if(check_lock_lists(0xffff) != 0)
		return(1);

	if(article_read(t,card_ex.addr,card_ex.docbox,card_ex.text_offset,card_ex.text_length,0,0,0) < 0)
		return(1);

	log_box = 255;
	if(log == 1)
	{
		log_box = box_table[card_ex.docbox].log_box;
		if(log_box == 255)
		{
			log_box = bounce_user->log;
		}
	}

	if(cptr->n_cats & STATUS_BIT_ATTACH)
		type |= 0x8;
	return(bounce_article(&t->text_base,0,t->text_length,user_number,type,log_box));
}   /* end of bounce_article2 */




void bounce_user_selected( int *hits)
/***********************************/
{
	user_select(NULL,mbox_list[hits[0]],0);
	dbox_setfield(dbox_bounce,4,get_user_id(current_user));
	bounce_user = current_user;
}   /* end of bounce_user_selected */



static void bounce_newsg_selected(int *hits)
/*****************************************/
{
	NEWSG *ng;
	reply_add_to_field(dbox_bounce,1,newsg_menu_name(hits[0],&ng));
}   /* end of bounce_newsg_selected */




static void reply_newsg_selected(int *hits)
/*****************************************/
{
	NEWSG *ng;
	reply_add_to_field(textr_menu->dbox_card,dbox_menu_field,newsg_menu_name(hits[0],&ng));

	if((ng != NULL) && (textr_menu != NULL))
	{
		if(ng->default_user > 0)
		{
			user_select(textr_menu,ng->default_user - 1,1);
		}
		if(ng->signature[0] > ' ')
		{
			strcpy(selected_sig,ng->signature);
			strcpy(textr_menu->selected_sig,selected_sig);
			dbox_setfield(textr_menu->dbox_card,0,selected_sig);
		}
	}
}   /* end of reply_newsg_selected */




void reply_addrbook_sig(TEXTR *t, ADDR_BOOK *a)
/*********************************************/
{
	char *sig;

	if((a == NULL) || (t == NULL))
		return;

	if(a->user > 0)
	{
		user_select(t,a->user - 1,1);
	}
	sig = &a->data[a->sig];

	if(sig[0] > ' ')
	{
		strcpy(selected_sig,sig);
		strcpy(t->selected_sig,sig);
		dbox_setfield(t->dbox_card,0,sig);
	}

	if(a->wordwrap >= 20)
		t->wordwrap = a->wordwrap;
}   /* end of reply_addrbook_sig */




BOOL dbox_bounce_raw_handler(dbox d, void *event, void *handle)
/*********************************************************/
{
	wimp_mousestr *mouse;
	wimp_eventstr *e = event;

	switch(e->e)
	{
	case wimp_EBUT:
		mouse = &e->data.but.m;
		switch(mouse->i)
		{
		case 1:
			if(mouse->bbits & 2)
			{
				address_insert(NULL,d,1);
				return(TRUE);
			}
			break;

		case 2:
			if(mouse->bbits & 1)  /* adjust */
				dbox_menu(newsg_make_menu(1),bounce_newsg_selected,mouse);
			else
				address_insert(NULL,d,1);
			return(TRUE);

		case 4:
			if(mouse->bbits & 7)
			{
				/* choose user_id */
				dbox_menu(make_users_menu(0),bounce_user_selected,mouse);
			}
			return(TRUE);
		}
	}
	return(FALSE);
}   /* end of dbox_bounce_raw_handler */




void dbox_bounce_handler(dbox d, void *handle)
/********************************************/
{
	FOLDREC *fr;
	CARD *cptr;
	TEXTR textr;
	int  log_flag;
	CARD *card_ptr = bounce_card_ptr;

	char dest[300];

	fr = (FOLDREC *)handle;

	if(dbox_get(d) != 0)
	{
		dbox_dispose(&d);
		return;
	}

	dbox_getfield(d,1,dest,sizeof(dest));
	log_flag = dbox_getnumeric(d,3);
	dbox_dispose(&d);

	reply_to_addr[0] = 0;

	if(reply_destinations(dest,bounce_user,1) == 0)
	{
		memset(&textr,0,sizeof(textr));

		if(card_ptr != NULL)
		{
			bounce_article2(&textr,card_ptr,-1,3,log_flag);
		}
		else
		{
			/* look for selected articles in the article list */
			list_enumerate_start(fr);
			while((cptr = list_enumerate_next(fr,fr->ixlist)) != NULL)
			{
				if(cptr->user & INET_HDR_MASK)
				{
					if(bounce_article2(&textr,cptr,-1,3,log_flag) < 0)
						break;
				}
				else
				{
					werr(0,"No header: '%s'",&cptr->data[cptr->d_title]);
				}
			}
		}

		if(textr.text_base != NULL)
		{
			flex_free((flex_ptr)&textr.text_base);
		}
	}

	remove(fname_temp2);
	set_boxlist_extent(0x27);
}   /* end of dbox_bounce_handler */




void bounce_messages(FOLDREC *fr, CARD *card_ptr)
/***********************************************/
/* Send a copy of the article as an email */
{
	int  user;

	bounce_card_ptr = card_ptr;

	dbox_bounce = dbox_new("BounceMsg");
	dbox_raw_eventhandler(dbox_bounce,dbox_bounce_raw_handler,NULL);
	dbox_eventhandler(dbox_bounce, dbox_bounce_handler,(void *)fr);

	bounce_user = current_user;
	if((card_ptr != NULL) && ((user = (card_ptr->user & 0x1f)) > 0))
		bounce_user = &options.mailbox[user-1];

	dbox_setfield(dbox_bounce,4,get_user_id(bounce_user));
	dbox_showstatic(dbox_bounce);
	icon_set_caret_pos(dbox_syshandle(dbox_bounce),1,0);  /* doesn't work */
}   /* end of bounce_messages */




void reply_write_references(TEXTR *t, FILE *f, int control)
/*********************************************************/
/* control: bit 0  inhibit In-reply-To    */
{
	int  i;
	int  c;
	int  total;
	int  excess;
	int  last_discard;
	int  msg_id_len;
	int  refs_count;
	int  count;
	int  quoting=0;
	char *p;
	ARTICLE_OUT *art_out;
	char buf[N_DEST_CHARS];

	art_out = t->art_out;

	if(art_out->quoted)
	{
		if(art_out->message_id[0] != 0)
		{
			fprintf(f,"References: ");
			count = 12;
			last_discard = -1;
			refs_count = 0;

			if(art_out->refs_length > 0)
			{
				if((refs_start == NULL) || (refs_start[0] != '<'))
				{
					werr(0,"References: line from original article is corrupted");
				}
				else
				{
					total = art_out->refs_length + strlen(art_out->message_id) + 2;
					excess = total + 12 - REFS_MAX_LENGTH;  /* new refs line would be too long by this amount */

					i = 0;
					while(i < art_out->refs_length)
					{
						/* get next reference */
						quoting = 0;
						msg_id_len = 0;
						p = buf;
						while(i < art_out->refs_length)
						{
							c = refs_start[i++];

							if(msg_id_len >= 80)
							{
								strcpy(buf,"  ");
								break;
							}

							if(msg_id_len > 0)
							{
								if(c == '"')
									quoting ^= 1;

								if((c <= ' ') && (quoting==0))
								{
									/* space within message id, implies closing > is missing */
									strcpy(buf,"  ");
									break;
								}
							}
							else
							{
								if(( c > ' ') && (c != '<'))
								{
									/* message id doesn't start with < */
									continue;    /* skip to next < */
								}
							}

							if(c >= ' ')
								msg_id_len++;

							*p++ = c;
							if(((quoting==0) && (c == '>')) || ((p-buf) >= (sizeof(buf)-1)))
							{
								*p = 0;
								break;
							}
						}

						/* skip refs if over excess length, but not the first ones */
						if((excess > 0) && (refs_count >= 5) && ((strstr(buf,"_-_@") == NULL)))
						{
							/* discard this references */
							if(last_discard != refs_count)
							{
								/* the previous ref was not discarded, indicate a gap with spaces */
								fprintf(f,"  ");
								excess += 2;
								count += 2;
							}

							excess -= strlen(buf);
							last_discard = refs_count;
						}
						else
						{
							/* write out this reference */
							refs_count++;

							if(strchr(buf,'\n') == NULL)
								count += strlen(buf);   /* keep count of line length */

							if(count >= REFS_FOLDING)
							{
								/* line length limit, fold the line */
								fputc('\n',f);
								count = strlen(buf);
								if(excess > 0)
									excess++;

								if(buf[0] != ' ')
								{
									fputc(' ',f);
									count++;
								}
							}
							fwrite(buf,1,strlen(buf),f);  /* can't use fprintf 'cos string might contain %s */
						}
					}
					fputc(' ',f);
				}
			}

			p = buf;
			while(isspace(*p)) p++;

			if(art_out->news_mail != X_NEWS)
			{
				if((art_out->in_reply_to[0] != 0) &&
						(strcmp(p,art_out->in_reply_to) != 0))
				{
					/* add the in-reply-to, if it's not already included in the references */
					fwrite(art_out->in_reply_to,1,strlen(art_out->in_reply_to),f);
					fputc(' ',f);
				}
			}
			fwrite(art_out->message_id,1,strlen(art_out->message_id),f);
			fputc('\n',f);
		}
	}
	else
	{
		/* forwarding a message, not quoting it.  Just copy the references line */
		if(art_out->refs_length > 0)
		{
			fprintf(f,"References: ");
			fwrite(refs_start,art_out->refs_length,1,f);
			fputc('\n',f);
		}
		if((art_out->in_reply_to[0] != 0) && ((control & 1) ==0))
		{
			fprintf(f,"In-Reply-To: ");
			fprintf(f,"%s\n",art_out->in_reply_to);
		}
	}

}   /* end of reply_write_references */




static int reply_news_header(TEXTR *t, FILE *f)
/*********************************************/
{
	int  c;
	int  i;
	char *p;
	char *p2;
	int  charset=1;
	char *from_addr;
	NEWSG *ng;
	OPTIONS_MAILBOX *user2;
	ARTICLE_OUT *art_out;
	char buf[N_DEST_CHARS];

	art_out = t->art_out;
	user2 = t->selected_user;
	from_addr = art_out->user_addr;

	if((t->charset > 1) && (t->charset < 100))
		charset = t->charset;

	fprintf(f,"Path: %s!%s\n",options.domain,options.u_name);
	fprintf(f,"From: %s <%s>\n",iso_encode_string(user_full_name(user2),1,"From:",t),from_addr);

	if(art_out->reply_to[0] != 0)
	{
		fprintf(f,"Reply-To: %s\n",art_out->reply_to);
	}


	if((art_out->supersede==1) && (art_out->message_id[0] != 0))
	{
		fprintf(f,"%scmsg cancel %s\n",string_subject,art_out->message_id);
		fprintf(f,"Control: cancel %s\n",art_out->message_id);
	}
	else
	{
		fprintf(f,string_subject);
#ifdef deleted
		if(art_out->keep_subject)
		{
			f_fold(f,art_out->subject,9,0);
		}
		else
#endif
		{
			p = iso_encode_string(art_out->subject,5,string_subject,t);
			if(p == NULL)
				return(1);
			f_fold(f,p,9,1);
		}
	}

	if((art_out->supersede==2) && (art_out->message_id[0] != 0))
	{
		fprintf(f,"Supersedes: %s\n",art_out->message_id);
	}

	strcpy(buf,art_out->newsgs);
	p = buf;

	for(;;)
	{
		while((*p != 0) && (isspace(*p))) p++;
		p2 = strpbrk(p," ,\t\n\r");
		if(p2 != NULL)
			*p2 = 0;

		if((ng = newsg_lookup(p)) != NULL)
		{
			art_out->pgp |= ng->sign_messages;
			art_out->ng_flags |= ng->ng_flags;
		}
		if(p2 == NULL)
			break;
		p = p2 + 1;
	}

	if(t->selected_user->flags & USEROPT_SIGN)
	{
		art_out->pgp |= 1;
	}


	p = buf;
	for(i=0; i<N_DEST_CHARS; i++)
	{
		c = art_out->newsgs[i];
		if(isspace(c))  continue;

		if((*p++ = c) == 0)
			break;
	}
	fprintf(f,"Newsgroups: %s\n",buf);
	if(isalnum(art_out->follow_up[0]))
	{
		fprintf(f,"Followup-To: %s\n",art_out->follow_up);
	}
	fprintf(f,"Date: %s\n",get_current_date_string(&art_out->date_enc));

	/* construct addr message-id and check it's valid */
	sprintf(buf,"%s@%s",get_user_id(user2),options.domain);
	for(i=0; i< N_MAIL_BOX; i++)
	{
		if(strcmp_lc(buf,options.mailbox[i].email_addr)==0)
			break;
	}
	if(i == N_MAIL_BOX)
	{
		sprintf(buf,from_addr);
	}

	fprintf(f,"Message-ID: <%s%s>\n",art_out->fname_out,buf);


	if(art_out->supersede==1)
	{
		/* Cancel request.  No references */
	}
	else
	{
		reply_write_references(t,f,1);
	}

	fprintf(f,"User-Agent: %s (RISC OS/%s)\n",mailer_name,os_version_string);

	add_sig(f,t,0x10+X_NEWS,t->selected_sig,0);   /* extra header lines */

	if((flag_organization==0) && (options.organization[0] != 0))
		fprintf(f,"Organization: %s\n",options.organization);

	if(art_out->encoding==2)
	{
		fprintf(f,"%s%s%d\n%s%s",mime_version,content_plain_iso,charset,content_encoding,content_encoding_8bit);
	}

	reply_multipart_header(t,f,X_NEWS);
	fprintf(f,"\n");
	return(0);
}   /* end of reply_news_header */








static int reply_mail_header(TEXTR *t, ARTICLE_OUT *art_out, FILE *f, FILE *f2, OPTIONS_MAILBOX *user)
/*********************************************************************************************/
{
	char *p;
	char *param;
	int  i;
	int  j;
	int  count;
	int  abandonned=0;
	ADDR_BOOK *a;
	NEWSG *ng;
	char *url;
	FILE *f_pgp=NULL;   /* list of addresses for encryption */
	char *from_addr;
	char buf[75];
	char buf2[80];

	reply_addr_chain = NULL;
	reply_addr_chain_next = &reply_addr_chain;

	from_addr = art_out->user_addr;

	fprintf(f,"%sFrom: %s <%s>",mime_version,iso_encode_string(user_full_name(user),0,"From:",t),from_addr);

	/* envelope file */
	env_header_lines = 1;
	if(options.mail_transport == X_ANT)
	{
		fprintf(f2,"MAIL FROM:<%s>\n",from_addr);
	}
	else
	{
		if(options.mail_transport == X_FREESMTP)
		{
			fprintf(f2,"GATE VIA:localhost\nMAIL FROM:<%s>\n",from_addr);
		}
		else
		{
			if(transport_opts & TOPS_MAIL_ENV_DOMAIN)
			{
				fprintf(f2,"%s",get_user_domain(user));
				env_header_lines++;
			}

			fprintf(f2,"\n%s\n",from_addr);
		}
	}


	p = art_out->reply_to;
	if(p[0] != 0)
	{
		if(strchr(p,'@') == NULL)
		{
			/* not an email address, look up the address book */
			if((p = addr_lookup(p)) == NULL)
			{
				werr(0,"Unrecognised name in Reply-To field");
				return(1);
			}
		}

		abandonned += reply_add_addr(4,p,1);
	}

	if((art_out->orig_cc_length > 0) && (art_out->orig_cc_length == strlen(art_out->cc))  &&
			(art_out->orig_cc_hash == get_hash9(art_out->cc)))
	{
		switch(query3("Include original Cc addresses ?","Yes","No","Change"))
		{
		case 0:
			art_out->cc[0]=0;
			break;

		case 1:
			break;

		case 2:
			return(1);
		}
	}
	else if(strstr(art_out->cc,"CC_LIST") != 0)
	{
		switch(query3("Include Cc addresses ?","Yes","No","Change"))
		{
		case 0:
			art_out->cc[0]=0;
			break;

		case 1:
			break;

		case 2:
			return(1);
		}
	}


	/* extract email address from destination name */
	count = 0;
	p = art_out->dest;
	do {
		i = get_addr_param(&p,&param,1);
		if(i & 2)
		{
			if((j = reply_mail_list(param,1)) != 0)
			{
				if(j == 1)
				{
					if(strchr(param,'@')==NULL)
						werr(0,"Name in 'To' field is not recognised");
					else
						werr(0,"Bad email address in 'To' field");
				}

				return(1);
			}
		}
		else
		{
			if(param == NULL)
				break;

			abandonned += reply_add_addr(0,param,1);   /* envelope file */
			if(abandonned==0)
			{
				/* is encryption required for this address ? */
				strncpy(buf,param,sizeof(buf));
				url = reply_extract_email_addr(buf,1);
				a = addr_lookup_url(url);
				if(a != NULL)
				{
					art_out->pgp |= (a->flags & 3);
					art_out->lock_log_copy = a->flags & 0x10;
				}

				sprintf(buf2,"mail.%s",url);
				ng = newsg_lookup2(buf2);
				if(ng != NULL)
				{
					art_out->pgp |= ng->sign_messages;
				}
			}
		}

		count++;
	} while((i & 1) == 0);


	/* sign or encrypt specified for this User */
	if(user->flags & USEROPT_SIGN)
		art_out->pgp |= 1;

	if(user->flags & USEROPT_ENCRYPT)
		art_out->pgp |= 2;


	if(count==0)
	{
		werr(0,"No address in 'To' field");
		return(1);
	}


	if(art_out->cc[0] != 0)
	{
		/* write out cc addresses, separated by ", " */
		count = 0;
		p = art_out->cc;
		do {
			i = get_addr_param(&p,&param,1);
			if(i & 2)
			{
				if((j = reply_mail_list(param,2)) != 0)
				{
					if(j == 1)
					{
						werr(0,"Unrecognised name in 'Cc' field");
					}
					return(1);
				}
			}
			else
			{
				if(param == NULL)
					break;

				abandonned += reply_add_addr(2,param,1);   /* envelope file */

				count++;
			}
		} while((i & 1) == 0);
	}

	if(art_out->bcc[0] != 0)
	{
		p = art_out->bcc;
		do {
			i = get_addr_param(&p,&param,0);
			if(i & 2)
			{
				if((j = reply_mail_list(param,3)) != 0)
				{
					if(j == 1)
					{
						werr(0,"Unrecognised name in 'Bcc' field");
					}
					return(1);
				}
			}
			else
			{
				if(param == NULL)
					break;

				abandonned += reply_add_addr(3,param,1);   /* envelope file */
			}
		} while(i == 0);
	}


	/* write out addresses */
	if(art_out->pgp & 2)
	{
		/* encrypting, we need a list of destination addresses for PGP */
		f_pgp = pgp_open_list();
	}

	for(i=1; i<=4; i++)
	{
		reply_addr_write(i,f,f2,f_pgp,t);
	}
	fprintf(f,"\n");
	if(f_pgp != NULL)
		fclose(f_pgp);
	reply_addr_free_chain();

	fprintf(f,"Date: %s\n",get_current_date_string(&art_out->date_enc));
	fprintf(f,string_subject);
#ifdef deleted
	if(art_out->keep_subject)
	{
		f_fold(f,art_out->subject,9,0);
	}
	else
#endif
	{
		p = iso_encode_string(art_out->subject,4,string_subject,t);
		if(p == NULL)
			return(1);
		f_fold(f,p,9,1);
	}

	fprintf(f,"Message-ID: <%s%s>\n",art_out->fname_out,from_addr);

	if((art_out->quoted) && (art_out->message_id[0] != 0))
	{
		fprintf(f,"In-Reply-To: %s\n",art_out->message_id);

	}
	if(t != NULL)
		reply_write_references(t,f,0);

	if(art_out->ack)
		fprintf(f,"Return-Receipt-To: %s\n",from_addr);

	if((user->flags & 0x10) == 0)
	{
		fprintf(f,"User-Agent: %s (RISC-OS/%s)\n",mailer_name,os_version_string);
	}

	add_sig(f,t,0x10+X_MAIL,t->selected_sig,0);   /* extra header lines */
	reply_addr_write(3,f,f2,NULL,t);   /* in case any Bcc added by extra header lines */
	reply_addr_free_chain();

	reply_multipart_header(t,f,X_MAIL);
	fputc('\n',f);

	return(abandonned);
}   /* end of reply_mail_header */





int reply_output_text(TEXTR *t, FILE *f, int *long_lines)
/*******************************************************/
/* Write out text, adding newlines
   Return the position in the text */
{
	int  c;
	int  n;
	int  i;
	int  n2;
	char *end;
	int  line;
	char *p;
	static char *hexchar = "0123456789ABCDEF";

//_kernel_register_slotextend(flex_dont_budge);
	p = t->text_base;
	*long_lines = 0;

	/* don't send trailing blanks */
	end = &p[t->text_body_end-1];
	while((end > p) && (*end <= ' '))
		end--;

	for(line=0; (line<t->n_lines) && (p <= end); line++)
	{
		n = t->line_tab[line];

		while(!isspace(p[n-1]) || ((p[n-1] != '\n') && (is_quoted_text(p))))
		{
			if(++line >= t->n_lines)
				break;

			/* don't wordwrap quoted text */
			n += t->line_tab[line];
		}

		if(p[n-1] <= ' ')
			n2 = n - 1;     /* remove trailing space/newline at end of line */
		else
			n2 = n;

		if((p[0]=='#') & (p[1]=='!'))
		{
			/* don't allow #! rnews or #! rmail at start of line */
			if((memcmp(&p[1],"! rnews",7)==0) || (memcmp(&p[1],"! rmail",7)==0))
				fputc(' ',f);
		}

		if(n2 > 80)
		{
			(*long_lines)++;
		}


		if(t->art_out->encoding == 1)
		{
			for(i=0; i<n2; i++)
			{
				if(((c = p[i]) >= 127) || (c == '='))
				{
					fputc('=',f);
					fputc(hexchar[c >> 4],f);
					fputc(hexchar[c & 0xf],f);
				}
				else
					fputc(c,f);
			}
		}
		else
		{
			for(i=0; i<n2; i++)
			{
				fputc(p[i],f);
			}
		}

		fputc('\n',f);
		p += n;
	}
	fputc('\n',f);

//_kernel_register_slotextend(flex_budge);

	return(t->text_body_end);
}   /* end of reply_output_text */





int copy_with_cr(char *from, char *to, char *append)
/**************************************************/
{
	FILE *f;
	FILE *f_out;
	int c;

	f = fopen_werr(from,"r",NULL);
	if(f==NULL)
		return(1);

	f_out = fopen_werr(to,append,NULL);
	if(f_out==NULL)
	{
		fclose(f);
		return(2);
	}

	while(!feof(f))
	{
		c = fgetc(f);
		if(feof(f)) break;

		if(c == '\n')
			fputc('\r',f_out);
		fputc(c,f_out);
	}
	fclose(f);

	fclose(f_out);
	return(0);
}   /* end of copy_with_cr */





void reply_close(TEXTR *t)
/************************/
{
	if(t==textr_spellcheck)
	{
		close_spell_window(t);
	}
	text_window_close(t);

	t->changed = 0;

	if(t->dbox_card == addr_insert_dbox)
		addr_insert_dbox = NULL;

	if(t->dbox_card != NULL)
		dbox_hide(t->dbox_card);

	wimp_close_wind(t->w_text);
	wimp_close_wind(t->w_attach);

	text_data_free(t);
}   /* end of reply_close */



void reply_check_pgp_title(ARTICLE_OUT *art_out, int type)
/********************************************************/
{
	char *p=NULL;
	char *p2=NULL;

	if((type==X_MAIL) && ((p = strstr(art_out->subject,"@~@~")) != NULL))
	{
		art_out->pgp |= 2;   /* encrypt */
	}
	else if((p2 = strstr(art_out->subject,":@:@")) != NULL)
	{
		art_out->pgp |= 1;   /* sign */
	}


	if((p==NULL) || ((p2!=NULL) && (p2<p)))
		p = p2;

	if(p != NULL)
	{
		/* remove the string */
		if(p[-1] == ' ')
			p--;
		*p = 0;
	}
}   /* end of reply_check_pgp_title */




int post_check_characters(TEXTR *t, int type)
/*******************************************/
{
	int  i;
	int  c;
	int  c2;
	int  c3;
	int  top_bit_set=0;
	int  reported=0;   /* 0=not reported, 1=ignore, 2=replace */
	int  expanded=0;
	FILE *f;
	char buf[80];

	/* look for character codes >= 128 */
	for(i=0; i<t->text_length; i++)
	{
		c = t->text_base[i];

		if((c==0xa0) && (i<t->text_body_end))
		{
			/* replace A0 by space in the text body */
			t->text_base[i] = ' ';
		}

		if((c < 0xa0) && ((c2 = check_char_tab[c]) > 0))
		{
			if(reported == 0)
			{
				c3 = c;
				if(c3 < ' ')  c3 = ' ';
				sprintf(buf,err_non_iso,"Message",c3,c);
				switch(query3(buf,"Auto-Replace","Continue","Edit"))
				{
				case 0:
					reported=1;
					break;
				case 1:
					reported=2;
					break;
				case 2:
					return(-1);
				}
			}

			if(reported==2)
			{

				if((c2=='i') || (c2=='l'))
				{
					move_down(t,i,1);
					expanded=1;
					t->text_base[i++] = 'f';   /* fi or fl ligature */
				}
				else if(c2=='.')
				{
					move_down(t,i,2);
					expanded=1;
					t->text_base[i++] = '.';   /* ... */
					t->text_base[i++] = '.';
				}

				t->text_base[i] = c = c2;
			}
		}

		if(c >= 127)
		{
			top_bit_set = 1;
		}
	}

	/* now check the signature */
	if(top_bit_set == 0)
	{
		sprintf(buf,"%s.Signatures.%s",path_choices,t->selected_sig);
		f = fopen(buf,"r");
		if(f != NULL)
		{
			while(!feof(f))
			{
				c = fgetc(f);
				if(c == EOF)
					break;
				if(c >= 127)
					top_bit_set = 1;
			}
			fclose(f);
		}
	}


	if(top_bit_set)
	{
		if((type == X_NEWS) || (t->attachments && (t->use_mime == 0)))
			t->art_out->encoding = 2;   /* use 8bit if we have a UUE attachment */
		else
			t->art_out->encoding = 1 + options.mail_8bit;
	}

	if(expanded)
	{
		calc_line_tab(t);   /* recalculate line_tab because we've added characters */
	}
	return(0);
}   /* end of post_check_characters */



int post_quoting_checks(TEXTR *t)
/*******************************/
{
	int  i;
	int  line;
	int  length;
	int  word_wrapped;
	int  lines_quoted;
	int  lines_unquoted;
	int  line_quoted;
	int  quoted_total;
	int  start;
	char *parent;
	CARD *parent_cptr;
	char *type_str;
	char buf[256];

	i = 0;
	lines_quoted = 0;
	lines_unquoted = 0;
	line_quoted = 0;
	quoted_total = 0;
	start=0;

#ifdef deleted
	if(memcmp("In article <",&t->text_base[0],12) == 0)
		start=2;   /* ignore attribution */
#endif
	start = 2;

	for(line=0; (line<t->n_lines) && (i <= t->text_body_end); line++)
	{
		length = t->line_tab[line];

		if(line >= start)
		{
			if((i==0) || (t->text_base[i-1] == '\n'))
			{
				/* ignore wordwrapped lines, which are not preceded by NL */

				line_quoted = is_quoted_text(&t->text_base[i]);
				word_wrapped = 0;
			}
			else
			{
				word_wrapped = 1;
			}

			if(line_quoted && (word_wrapped == 0))
			{
				/* don't count word_wrapped lines which follow quoted lines */
				if(length > 4)
				{
					lines_quoted++;
					quoted_total += (length - line_quoted*2);
				}
			}
			else if(!line_quoted)
			{
				if((length > 2) || isalnum(t->text_base[i]))
					lines_unquoted++;
			}
		}
		i += length;
	}
	if((lines_unquoted == 0) && (lines_quoted > 0))
	{
		werr(0,"No unquoted text");
		return(6);
	}

	if(lines_quoted == 0)
	{
		parent = t->art_out->message_id;

		if(parent[0] != 0)
		{
			parent_cptr = msgid_lookup(gethash32(parent),NULL,0);
			if(parent_cptr != NULL)
			{
				parent = &parent_cptr->data[parent_cptr->d_title];
			}

			if(strstr(t->art_out->subject,parent) == NULL)
			{
				sprintf(buf,"No quoted text. Is this meant to be a reply to '%s' ?",parent);
				switch(query3(buf,"Cancel","Not a reply","A reply"))
				{
				case 0:
					t->art_out->message_id[0]=0;  /* remove reference */
					break;
				case 1:
					return(7);
				}
			}
		}
	}

	if(((lines_quoted > 20) && ((lines_unquoted*2) < lines_quoted)) ||
			((lines_quoted > 15) && (lines_unquoted < 2)) ||
			((quoted_total > 900) && (lines_unquoted < 2)))
	{
		if(t->art_out->mailing_list)
			type_str = "mailing list";
		else
			type_str = "news";
		sprintf(buf,"Excessive quoting in %s message",type_str);
		if(!query(buf,"POST"))
			return(8);
	}

	return(0);
}   /* end of post_quoting_checks */




int post_mail(TEXTR *t, char *news_copy, int dont_close)
/******************************************************/
/* news_copy 1 = an email copy of a nws posting */
{
	int  i;
	ARTICLE_OUT *art_out;
	FILE *f;
	FILE *f2;
	int  length;
	int  locked;
	int  failed=0;
	int  text_end;
	int  dest_count2;
	int  log_box;
	int  long_lines=0;
	int  msg_id_type;
	int  cc_bit = 0;
	int  pgp_started;
	int  start_addr;
	int  max_addr=999;  /* max number of addressees */
	char *fname_log;
	char fname_out[16];
	char fname_out2[16];
	char fname[150];
	char fname2[150];

	art_out = t->art_out;
	own_address_flag = 0;
	destination_count = 0;
	bcc_count = 0;



	if(t->selected_user->flags & 2)
	{
		werr(0,"You are not allowed to post email from user '%s'",t->selected_user->full_name);
		return(1);
	}
	if(options.mail_out[0] == 0)
	{
		werr(0,"Can't send mail with this transport");
		return(2);
	}

	/* to quoting checks if this is a mailing list message */
	if(t->art_out->mailing_list)
	{
		if(post_quoting_checks(t) != 0)
			return(3);
	}

	check_ramfs2();

	if(art_out->fname_out[0] == 0)
	{
		/* not yet set */
		if(t->attachments > 0)
			msg_id_type = 9;
		else
			msg_id_type = 1;
		strcpy(art_out->fname_out,get_message_id(0,msg_id_type));
	}


	if(post_check_characters(t,X_MAIL) < 0)
		return(1);


	f2 = fopen_werr(fname_temp2,"w",NULL);
	if(f2==NULL) return(2);

	f = fopen_werr(fname_temp,"w",NULL);
	if(f==NULL) return(1);


	if(art_out->keep_subject == 0)
		reply_check_pgp_title(art_out,X_MAIL);


	if((t->attachments > 0) && ((t->text_body_end - t->text_start) <= 1)
			&& (t->text_base[t->text_start] <= ' '))
	{
		/* no text */
		art_out->encoding = -1;   /* no text */
		text_end = t->text_body_end;
	}

	failed = reply_mail_header(t,art_out,f,f2,t->selected_user);


	if(failed)
	{
		fclose(f);
		fclose(f2);

		/* delete the mail-out and envelope files */
		file_delete(fname_temp);
		file_delete(fname_temp2);
		return(1);
	}

	pgp_started = pgp_start_text(&f,art_out->pgp);

	if(t->boundary_string_len > 0)
	{
		reply_content_type(t,f);
		fputc('\n',f);
	}

	if((news_copy != NULL) && (news_copy[0] != 0))
	{
		fprintf(f,"[Email copy of news posting to %s]\n\n",news_copy);
	}


	if(art_out->encoding >= 0)
	{
		/* text section is not empty */
		text_end = reply_output_text(t,f,&long_lines);
		failed = add_sig(f,t,X_MAIL,t->selected_sig,t->selected_user->tags);

		if(!failed && (long_lines > 0))
		{
			if(query2(msg_long_lines,"Change","Post"))
				failed = 1;
		}
		if(failed && pgp_started)
		{
			pgp_end_text(&f,-1,0);
		}
	}


	if(!failed)
	{
		/* any attachments */
		length = t->text_length - text_end;
		if(length > 1)
		{
			fwrite_werr(&t->text_base[text_end],length,1,f);
		}

		if(t->boundary_string_len > 0)
		{
			fprintf(f,"\n--%s--\n",t->boundary_string);
		}

		failed = pgp_end_text(&f,art_out->pgp,t->selected_user);
	}


	fclose(f);
	fclose(f2);

#ifdef deleted
// moved higher up, before pgp_end */
	if(!failed && (long_lines > 0))
	{
		if(query2(msg_long_lines,"Change","Post"))
			failed = 1;
	}
#endif

	if(failed)
	{
		/* delete the mail-out and envelope files */
		file_delete(fname_temp);
		file_delete(fname_temp2);
		return(1);
	}

	visdelay2_begin();


	if(get_button_state(t->w_card,2) != 0)
		locked = 0x200;
	else
		locked = 0;

	if(art_out->lock_log_copy)
		locked = 0x200;    /* address book specifies lock the log copy */

	log_box = t->selected_user->log;
	if(t->cptr != NULL)
	{
		/* does the box of the original message specify that replies are to be logged
		   in the same box ? */
		i = t->cptr->date_box >> 26;
		if(box_table[i].log_box != 255)
			log_box = box_table[i].log_box;
	}

	strcpy(fname_out,art_out->fname_out);  /* because t and art_out will be freed */
	strcpy(fname_out2,fname_out);

	fname_log = fname_temp;

	dest_count2 = destination_count;
	start_addr = 0;

	if(options.limit_recipients > 0)
		max_addr = options.limit_recipients;

	while(dest_count2 > 0)
	{
		sprintf(fname,"%s.%s",options.mail_out,fname_out2);
		sprintf(fname2,"%s.%s",options.mail_envs,fname_out2);

		if(transport_opts & TOPS_MAIL_CRLF)
		{
			if((transport_opts & TOPS_ENVS_FILES) == 0)
			{
				if(copy_env_file(fname_temp2,fname,2,start_addr,max_addr) != 0)
					return(1);
				if(copy_with_cr(fname_temp,fname,"a") != 0)
					return(1);
			}
			else
			{
				if(copy_env_file(fname_temp2,fname2,1,start_addr,max_addr) != 0)
					return(1);
				if(copy_with_cr(fname_temp,fname,"w") != 0)
					return(1);
			}

			if(transport_opts & TOPS_MAIL_DOT)
			{
				f = fopen_werr(fname,"a",NULL);
				if(f != NULL)
				{
					fprintf(f,".\r\n");    /* should check whether it already ends in NL */
					fclose(f);
				}
			}

		}
		else
		{
			if(copy_env_file(fname_temp2,fname2,0,start_addr,max_addr) != 0)
				return(1);
			if(file_copy(fname_temp,fname) != NULL)
				return(1);
			/*  fname_log = fname; */ /* only if file is moved not copied */
		}

		/* continue with a second copy if there are more than the max number of
		   addressees */
		dest_count2 -= max_addr;
		start_addr += max_addr;
		strcpy(fname_out2,get_message_id(0,msg_id_type));  /* change filename */
	}


	if((news_copy == NULL) && (dont_close==0))
		text_data_free1(t);


	if(own_address_flag)
	{
		load_article(fname_log,0xfff,0x02,-1,NULL,0);
	}

	/* put the reply in the mail log box */
	if(dest_count2 > 1)
		cc_bit = 0x400;  /* more than one destination */
	load_article(fname_log,0xfff,0x13+locked+cc_bit,log_box,fname_out,t->selected_user_num+1);


	if(fname_log == fname_temp)
	{
		file_delete(fname_temp2);
		file_delete(fname_temp);
	}

	visdelay2_end();
	return(0);
}   /* end of post_mail */





int post_news(TEXTR *t, int dont_close)
/*************************************/
{
	char *p;
	FILE *f;
	ARTICLE_OUT *art_out;
	int  i;
	int  length;
	int  text_end;
	int  n_groups;
	int  locked = 0;
	int  dot_count;
	int  error;
	int  failed=0;
	int  log_box;
	int  long_lines;
	int  pgp_started;
	char *fname_log;
	char fname_out[16];
	char fname[160];

	check_ramfs2();

	if(options.news_out[0] == 0)
	{
		werr(0,"Can't post news with this transport");
	}

	art_out = t->art_out;

	if(t->selected_user->flags & 1)
	{
		werr(0,"You are not allowed to post news from user '%s'",t->selected_user->full_name);
		return(1);
	}
	if(t->selected_user->mail_list_server != 0)
	{
		if(query("You're posting from your mailing list server address","POST")==0)
			return(1);
	}

	p = art_out->newsgs;
	n_groups = 1;
	dot_count = 0;
	error=0;
	while(*p != 0)
	{
		if(*p == '.')
			dot_count++;

		if(*p == ',')
		{
			n_groups++;
			if(dot_count == 0)
				error = 1;
			dot_count = 0;
		}
		p++;
	}
	if(error || (dot_count == 0))
	{
		if(art_out->newsgs[0] == 0)
		{
			werr(0,"No newsgroup specified");
			return(6);
		}
		else
		{
			if(query(err_newsgroups_no_dot,"POST")==0)
				return(4);
		}
	}

	if(n_groups > 1)
	{
		sprintf(fname,"Are you sure you want to post to %d groups ?",n_groups);
		beep();
		if(!query(fname,"POST"))
			return(2);

		if(n_groups > 3)
		{
			beep();
			sprintf(fname,"You *really* shouldn't post to %d groups !",n_groups);
			if(!query(fname,"POST"))
				return(3);
		}

		if(art_out->follow_up[0] == 0)
		{
			sprintf(fname,"Do you want to set Follow Ups so that any replies are not posted to %d groups as well ?",n_groups);
			if(!query2(fname,"POST","Change"))
				return(3);
		}
	}

	if(t->attachments>0)
	{
		if((strstr(art_out->newsgs,"binar")==NULL) && (strstr(art_out->newsgs,"pictur")==NULL))
		{
			if(query("Attempt to post an attachment to a non-binaries newsgroup.",NULL)==0)
				return(5);
		}
		else
		{
			if(art_out->follow_up[0] == 0)
			{
				if(query2("You should set Follow Ups to a non-binary newsgroup","Change","Post"))
					return(6);
			}
		}
	}


	/* check for excessive quoting */
	if(post_quoting_checks(t) != 0)
		return(7);



	sprintf(fname,"%s.%s",options.news_out,art_out->fname_out);

	if(post_check_characters(t,X_NEWS) < 0)
		return(1);


	f = fopen_werr(fname_temp,"w","News Out ");
	if(f==NULL) return(1);


	if(transport_opts & TOPS_NEWS_ANT)
	{
		fprintf(f,"POST +00000128\n");
	}

	reply_check_pgp_title(art_out,X_NEWS);

	failed = reply_news_header(t,f);

	if(!failed)
	{
		pgp_started = pgp_start_text(&f,art_out->pgp);

		if(t->boundary_string_len > 0)
		{
			reply_content_type(t,f);
			fputc('\n',f);
		}

		text_end = reply_output_text(t,f,&long_lines);

		if(art_out->supersede != 1)
		{
			failed = add_sig(f,t,X_NEWS,t->selected_sig,options.news_tags);
			if(failed && pgp_started)
			{
				pgp_end_text(&f,-1,0);
			}
		}
	}

	if(!failed)
	{
		/* any attachments */
		length = t->text_length - text_end;
		if(length > 1)
		{
			fwrite_werr(&t->text_base[text_end],length,1,f);
		}

		if(t->boundary_string_len > 0)
		{
			fprintf(f,"\n--%s\n",t->boundary_string);
		}


		failed = pgp_end_text(&f,art_out->pgp,t->selected_user);
	}

	if(!failed && (long_lines > 0))
	{
		if(query2(msg_long_lines,"Change","Post"))
			failed = 1;
	}

	if(!failed && (art_out->ng_flags & NG_READ_ONLY))
	{
		if(query("Post to a newsgroup that you've set as 'Read Only' ?","Post")==0)
			failed = 1;
	}


	if(failed)
	{
		fclose(f);
		remove(fname_temp);
		return(7);
	}

	fclose(f);


	log_box = options.news_log;
	if(t->cptr != NULL)
	{
		/* does the box of the original message specify that replies are to be logged
		   in the same box ? */
		i = t->cptr->date_box >> 26;
		if(box_table[i].log_box != 255)
			log_box = box_table[i].log_box;
	}

	if(get_button_state(t->w_card,2) != 0)
		locked = 0x200;

	fname_log = fname_temp;
	strcpy(fname_out,art_out->fname_out);

	if(transport_opts & TOPS_NEWS_CRLF)
	{
		/* add CR before each LF */
		if(copy_with_cr(fname_temp,fname,"w") != 0)
			return(1);


		if(transport_opts & TOPS_NEWS_DOT)
		{
			f = fopen_werr(fname,"a",NULL);
			if(f != NULL)
			{
				fprintf(f,".\r\n");    /* should check whether it already ends in NL */
				fclose(f);
			}
		}
	}
	else
	{
		if(file_move(fname_temp,fname) != NULL)
			return(1);
		fname_log = fname;
	}


	if(dont_close==0)
		text_data_free1(t);

	load_article(fname_log,0xfff,0x53+locked,log_box,fname_out,t->selected_user_num+1);


	if(fname_log == fname_temp)
	{
		file_delete(fname_temp);
	}

	return(0);
}   /* end of post_news */




int get_quote_string_length(char *start,int *blanks)
/**************************************************/
{
	char *p;
	char *p2;
	p = start;
	while((*p != 0) && (strchr(" >|:]}",*p) != NULL)) p++;
	p2 = p;

	while((p2 > start) && (p2[-1] == ' ')) p2--;

	if(blanks != NULL)
		*blanks = p-p2;
	return(p2 - start);
}   /* end of get_quote_string_length */



void strip_article_blanks(TEXTR *t)
/*********************************/
/* Strip trailing blanks, just leave a NL */
{
	int  i;
	char *p;

	p = t->text_base;
	i = t->text_length-1;

	while((i>0) && (p[i] <= ' '))
	{
		i--;
	}
	p[++i] ='\n';
	calc_line_tab(t);

	t->text_length = i+1;
	if(t->text_body_end > t->text_length)
		t->text_body_end = t->text_length;

	if(t->cursor_index >= t->text_length)
	{
		t->cursor_index = t->text_length - 1;
		set_caret_pos(t);
	}
}   /* end of strip_article_blanks */


char *get_sig_name(int count, char *name)
/***************************************/
{
	os_error *error;
	os_regset regs;
	char buf[48];
	char sig_path[160];

	if(count == 0)
	{
		strcpy(name,"");
	}
	else
	{
		sprintf(sig_path,"%s.Signatures",path_choices);

		regs.r[0] = 10;
		regs.r[1] = (int)sig_path;
		regs.r[2] = (int)buf;
		regs.r[3] = 1;
		regs.r[4] = 0;
		regs.r[5] = sizeof(buf);
		regs.r[6] = 0;

		while((count-- >= 1) && (regs.r[3] > 0))
		{
			error = os_swix(0x0c,&regs);           /* OS_GBPB 10, read directory entries */
			if((error != NULL) || (regs.r[3] == 0))
				break;
		}
		strcpy(name,&buf[20]);
	}
	return(name);
}   /* end of get_sig_name */



void reply_sig_selected(int *hits)
/********************************/
{
	get_sig_name(hits[0],selected_sig);
	strcpy(textr_menu->selected_sig,selected_sig);

	dbox_setfield(textr_menu->dbox_card,0,selected_sig);
}   /* end of reply_sig_selected */



void reply_user_selected(int *hits)
/*********************************/
{
	user_select(textr_menu,mbox_list[hits[0]],0);
}   /* end of reply_user_selected */





void reply_mime_selected(int *hits)
/*********************************/
{
	if(hits[0] == 3)
	{
		/* save in options */
		options.use_mime = textr_menu->use_mime;
		options_save();
		return;
	}

	if(textr_menu->attachments)
		werr(0,"Can't change attachment type while you have attachments");
	else
	{
		textr_menu->use_mime = hits[0];
		dbox_setfield(textr_menu->dbox_card,4,mime_style_names[hits[0]]);
	}
}   /* end of reply_mime_selected */




wimp_menustr *sigs_make_menu(int type, char *first)
/*************************************************/
/* Make menu of signature files or distribution lists */
{
	int  count=0;
	os_error *error;
	os_regset regs;
	struct {
		int  spare[5];
		int  ftype;
		char name[32];
	} buf;

	char sig_path[160];

	if(type==0)
		sprintf(sig_path,"%s.Signatures",path_choices);
	else
		sprintf(sig_path,"%s.MailLists",path_choices);

	regs.r[0] = 12;
	regs.r[1] = (int)sig_path;
	regs.r[2] = (int)&buf;
	regs.r[3] = 1;
	regs.r[4] = 0;
	regs.r[5] = sizeof(buf);
	regs.r[6] = 0;

	if(menu_sigs != 0)
		menu_dispose(&menu_sigs,0);

	if(type==0)
		menu_sigs = menu_new("Signatures",first);
	else
		menu_sigs = menu_new("Distn Lists",first);

	while(regs.r[3] > 0)
	{
		error = os_swix(0x0c,&regs);           /* OS_GBPB 10, read directory entries */
		if((error != NULL) || (regs.r[3] == 0))
			break;

		if(buf.ftype != 0xfff)
			continue;    /* chcek for filetype = TEXT */

		menu_extend(menu_sigs,buf.name);
		count++;

		if(type==0)
		{
			if(strlen(buf.name) > 11)
			{
				/* only allow sig filenames up to 11 chars (limit in NEWSG data) */
				menu_setflags(menu_sigs,count+1,0,1);  /* fade this entry */
			}
		}
	}
	wmenu_sigs = (wimp_menustr *)menu_syshandle(menu_sigs);
	return(wmenu_sigs);
}   /* end of sigs_make_menu */


int convert_to_palette(unsigned int palette)
/******************************************/
{
	unsigned int  r,g,b;

	r = (palette >> 16)& 0xff;
	g = (palette >> 8) & 0xff;
	b = (palette) & 0xff;

	return( (b<<24) | (g<<16) | (r<<8) );
}   /* end of convert_to_palette */



int reply_start_OLE(TEXTR *t)
/***************************/
{
	char *fname_ole;
	FILE *f_ole;

	fname_ole = get_temp_fname();

	f_ole = fopen_werr(fname_ole,"w",NULL);
	if(f_ole == NULL)
		return(-1);

	fwrite(t->text_base,1,t->text_body_end,f_ole);
	fclose(f_ole);

	OLE_start(fname_ole,0xfff,2,t->w_card,0,(void *)t);

	fade_ext_edit(t->w_card,wimp_INOSELECT);
	t->ole = 1;
	t->changed = 1;
	return(0);
}   /* end of reply_start_OLE */




BOOL dbox_editbut_raw_handler(dbox d, void *event, void *handle)
/**************************************************************/
{
	wimp_mousestr *mouse;
	int  c;
	int bbits;
	int  icon_state;
	int  field;
	int  max_field;
	TEXTR *t;
	int  filetype;
	char *filename;
	ARTICLE_OUT *art_out;
	wimp_eventstr *e = event;
	wimp_redrawstr r;
	char buf[128];

	t = (TEXTR *)handle;
	art_out = t->art_out;

	switch(e->e)
	{
	case wimp_EREDRAW:
		r.w = e->data.o.w;
		wimp_redraw_wind(&r, &c);

		while(c)
		{
			c = convert_to_palette(options.text_colrs[t->text_type+10-X_MAIL]);
			if(c != 0xdddddd00)
			{
				/* don't fill with wimp colour 1, leave marbled background */
				os_swi6(0x40743,c,0,0,0,0,0);
				bbc_rectanglefill(r.g.x0,r.g.y0,r.g.x1-r.g.x0, r.g.y1-r.g.y0);
			}
			wimp_get_rectangle(&r, &c);
		}
		break;

	case wimp_EOPEN:
		open_card_window(&e->data.o,t);
		return(TRUE);
		break;

	case wimp_ECLOSE:
		break;

	case wimp_EBUT:
		/* click on icon.  get icon number. */
		mouse = &e->data.but.m;
		bbits = mouse->bbits;
		icon_state = get_button_state(t->w_card,mouse->i);

		textr_menu = t;
		switch(dbox_menu_field = field = mouse->i)
		{
		case 5:   /* lips */
			if(bbits & 4)
			{
				/* select button */
				if(akbd_pollsh())
					set_scroll_as_you_speak(t,1);  /* resume scrolling */
				else
					toggle_speak(t,icon_state);
			}
			else if(bbits & 1)
			{
				speak_stop(t);   /* to de-select the icon button */
				options_speak();
			}
			return(TRUE);

		case 0:   /* signature menu, not for adjust */
			if(bbits & 6)
			{
				dbox_menu(sigs_make_menu(0,"(none)"),reply_sig_selected,mouse);
			}
			else
			{
				/* adjust-click, show the sig file */
				sprintf(buf,"%s.Signatures.%s",path_choices,t->selected_sig);
				dataopen(buf,0xfff);
			}
			return(TRUE);

		case 4:   /* UUE/MIME */
			dbox_menu(wmenu_mime_styles,reply_mime_selected,mouse);
			return(TRUE);

		case 6:   /* user menu */
			if(bbits & 7)
			{
				/* choose user_id */
				dbox_menu(make_users_menu(0),reply_user_selected,mouse);
			}
			return(TRUE);

		case 18:
		case 19:
		case 20:
		case 21:
			field -= 9;  /* convert to 9 to 12 */
			dbox_menu_field = field;
			bbits |= 2;
			/* drop through */
		case 9:
		case 10:
		case 11:
		case 12:
			if((field==10) && (bbits == wimp_BLEFT))
			{
				dbox_getfield(d,10,art_out->cc,sizeof(art_out->cc));
				if(strstr(art_out->cc,"CC_LIST") != NULL)
				{
					sprintf(buf,"%s.Maillists.%s",path_choices,cc_list_name(t,"CC"));
					dataopen(buf,0xfff);
					return(TRUE);
				}
			}

			if(bbits & 2)
			{
				if((field==11) || (art_out->news_mail==X_MAIL))
				{
					if(bbits & 1)  /* adjust */
						dbox_menu(newsg_make_menu(1),reply_newsg_selected,mouse);
					else
						address_insert(t,d,field);
					return(TRUE);
				}
				else if(art_out->news_mail == X_NEWS)
				{
					dbox_menu(newsg_make_menu(field==10? 0x100:0),reply_newsg_selected,mouse);
					return(TRUE);
				}
			}
			break;
		}
		break;


	case wimp_EKEY:
		c = e->data.key.chcode;
		field = e->data.key.c.i;

		if(art_out->news_mail == X_MAIL)
		{
			if(t->button_bar_height == MAIL_BUTTON_BAR_HEIGHT)
				max_field = 9;
			else
				max_field = 12;
		}
		else
		{
			if(t->button_bar_height == NEWS_BUTTON_BAR_HEIGHT)
				max_field = 10;
			else
				max_field = 11;
		}

		if((c == KEY_UP) || (c == KEY_SHIFT_TAB))
		{
			if(field == 8)
			{
				icon_set_caret_pos(t->w_card,max_field,1);
				return(TRUE);
			}
		}

		if((c == '\r') || (c == KEY_DOWN) || (c == KEY_TAB))
		{
			if(options.ext_edit)
			{
				if((c == '\r') || (field == max_field))
				{
					if((get_icon_state(t->w_card,1) & wimp_INOSELECT)==0)
						reply_start_OLE(t);
					return(TRUE);
				}
			}
			else if(field == max_field)
			{
				t->cursor_index = 0;
				t->cursor_line_start = 0;
				t->cursor_line = 0;
				set_caret_pos(t);
				return(TRUE);
			}
		}

		if(key_text_window1(c,t))
			return(TRUE);
		break;

	case wimp_ESEND:
	case wimp_ESENDWANTACK:
		switch(e->data.msg.hdr.action)
		{
		case wimp_MDATASAVE:
			xferrecv_wimpscrap(e);
			return(TRUE);

		case wimp_MDATALOAD:
			filetype = xferrecv_checkinsert(&filename);

			if((e->data.msg.data.dataload.i >> 16) == 1)
				return(FALSE);    /* clipboard response on dbox icon */

			attach_create(t,filename,wimpscrap_check(filename),filetype);
			wimpscrap_check_clear();
			xferrecv_insertfileok();
			return(TRUE);
		}
		break;
	}

	if(t->text_type == X_NEWS)
	{
		c = help_handler(event,HELP_NEWS);
		if(c == TRUE)
			return(c);
	}
	return(help_handler(event,HELP_MAIL));
}   /* end of dbox_editbut_raw_handler */


void reply_set_status(FOLDREC *fr, CARD *cptr)
/********************************************/
/* Set status to Read and mark as Replied */
{
	int  status;
	TEXTR *t;
	int  ix;

	if(cptr != NULL)
	{
		status = cptr->status & STATUS_MASK;
		if(status == STATUS_HIDDEN)
			return;   /* or else we'd change HIDDEN to DRAFT */

		if(status <= STATUS_UNREAD)
			status = STATUS_READ;   /* change to read */

		/* set replied bit, unless this is a reply to an outgoing mesage
		   in which case reserve the OG bit to indicate the message has appeared
		   in the newsgroup */
		if((cptr->status & STATUS_BIT_OG) == 0)
		{
			cptr->status = (cptr->status & ~STATUS_MASK) | status | STATUS_BIT_REPLIED;

			for(ix=0; ix<N_TEXT_DATA; ix++)
			{
				t = text_data_record[ix];
				if((t != NULL) && (t->text_type <= X_VIEW2))
				{
					if(cptr == t->cardex->card_ptr)
					{
						t->cardex->status = status;
						t->cardex->status_other |= STATUS_BIT_REPLIED;
					}
				}
			}
		}

		article_update(fr,cptr,NULL,0,0);
		redraw_list_lines(fr,0);

	}
}   /* end of reply_set_status */




int any_lower_case(char *string)
/******************************/
{
	int c;
	int alpha=0;

	while((c = *string++) != 0)
	{
		if(islower(c))
			return(2);
		if(isalpha(c))
			alpha=1;
	}
	if(alpha)
		return(1);
	return(0);
}   /* end of any_lower_case */



int strcmp_printable(char *a, char *b)
/************************************/
/* Compare, replacing control characters in string a by spaces */
{
	int  c;
	int  i;

	for(;;)
	{
		c = *a++;
		if((c < ' ') && (c != 0) && (c != '\n') && (c != '\r'))
			c = ' ';
		if((i = c - *b++) != 0)
			return(i);
		if(c == 0)
			return(0);
	}
}   /* end of strcmp_printable */







void reply_remove_draft(CARD *cptr_save, int temporary)
/*****************************************************/
/* temporary=1  only remove a temporary article */
{
	if((cptr_save != NULL) && ((cptr_save->status & STATUS_MASK2) == STATUS_DRAFT))
	{
		if((temporary==0) || (cptr_save->status & STATUS_BIT_HDR_ONLY))
		{
			/* don't show the deleted Draft message in the Bin box */
			cptr_save->status = (cptr_save->status & ~STATUS_MASK2) + STATUS_HIDDEN;
			cardfile_remove(NULL,cptr_save,BOX_BIN);
		}
	}
}   /* end of reply_remove_draft */




void reply_save_draft(TEXTR *t, int temporary)
/********************************************/
/* Save current write news/mail article with STATUS_DRAFT so
   that it can be retrieved later */

/* TO DO:  include message-id of original article being replied to
      delete a previous STATUS_DRAFT article if there is one */
{
	int  i;
	FILE *f;
	int  user;
	int  box;
	int  action;
	CARD *cptr_prev;
	char *source;
	char buf[300];

	f = fopen_werr(fname_temp4,"w",NULL);
	if(f==NULL)
		return;

	dbox_getfield(t->dbox_card,8,buf,sizeof(buf));
	fprintf(f,"Subject: %s\n",buf);
	dbox_getfield(t->dbox_card,9,buf,sizeof(buf));
	if(t->text_type == X_NEWS)
	{
		fprintf(f,"Newsgroups: %s\n",buf);
		fprintf(f,"From: %s\n",buf);
	}
	else
	{
		fprintf(f,"From: %s\n",buf);
		if(t->cptr != NULL)
		{
			source = expand_source(t->cptr->source,0);
			fprintf(f,"X-Pluto-Source: %s\n",source);
		}
	}
	dbox_getfield(t->dbox_card,10,buf,sizeof(buf));
	if(buf[0] != 0)
		fprintf(f,"Cc: %s\n",buf);

	reply_write_references(t,f,0);

	if(t->art_out->message_id[0] != 0)
		fprintf(f,"In-Reply-To: %s\n",t->art_out->message_id);

	reply_multipart_header(t,f,t->text_type);
	if(t->boundary_string_len > 0)
	{
		reply_content_type(t,f);
	}

	fputc('\n',f);


	for(i=0; i<t->text_length; i++)
	{
		fputc(t->text_base[i],f);
	}
	fclose(f);

	user = t->selected_user_num;
	if(t->text_type == X_NEWS)
	{
		action = 0x40;
		box = options.news_log;
	}
	else
	{
		action = 0x80;
		box = options.mailbox[user].log;
	}
	if(t->cptr != NULL)
	{
		/* does the box of the original message specify that replies are to be logged
		   in the same box ? */
		i = t->cptr->date_box >> 26;
		if(box_table[i].log_box != 255)
			box = box_table[i].log_box;
	}
	if(options.draft_box != BOX_BIN)
	{
		box = options.draft_box;
	}

	cptr_prev = t->cptr_save;

	if((cptr_prev != NULL) && ((cptr_prev->status & STATUS_BIT_HDR_ONLY)==0))
		temporary = 0;  /* it's already been made permanent */

	if(temporary)
		action |= 0x20000;   /* set header-only bit to indicate temporary article */

	/* delete previous saved copy */
	if((cptr_prev != NULL) && ((cptr_prev->status & STATUS_MASK2)==STATUS_DRAFT))
	{
		cptr_prev->date_box = (cptr_prev->date_box & DATE_MASK) + ((unsigned)BOX_BIN << 26);
		cardfile_remove(NULL,cptr_prev,BOX_BIN);
	}

	t->cptr_save = load_article(fname_temp4,0xfff,0x10000+action,box,NULL,user+1);

	if((t->cptr_save != NULL) && (temporary==0))
		t->changed = 0;

	file_delete(fname_temp4);
}   /* end of reply_save_draft */





int reply_check_changed(TEXTR *t)
/*******************************/
{
	int  i;
	static char *msg = "Message not posted, Discard ?";

	if(t->changed)
	{
		i = query3(msg,"Discard","Cancel","Keep Draft");
		if(i == 0)
			return(1);
		if(i == 2)
			reply_save_draft(t,0);

	}
	return(0);
}   /* end of reply_check_changed */





void reply_post_message(TEXTR *t)
/*******************************/
{
	dbox d;
	int  result;
	ARTICLE_OUT *art_out;
	FOLDREC *fr;
	CARD *cptr = NULL;
	CARD *cptr_save = NULL;
	int  i;
	int  dont_close;
	int  save_subj_len;
	int  re_prefix;
	int  msg_id_type;
	char *from_addr;
	dbox d_from;
	char save_subj[N_SUBJECT+1];

	if(check_lock_lists(0xffff) != 0)
		return;

	dont_close = dbox_persist();

	d = t->dbox_card;
	art_out = t->art_out;
	art_out->news_mail = t->text_type;
	art_out->fname_out[0] = 0;
	fr = t->fr;

	/* save a copy */
	if(options.autosave != 0)
		text_autosave2(t);

	cptr = t->cptr;
	cptr_save = t->cptr_save;

	from_addr = "";
	if(t->selected_user != NULL)
	{
		from_addr = t->selected_user->email_addr;
	}

	if((strchr(from_addr,'*')!= NULL) && (art_out->user_addr[0] != 0))
		from_addr = art_out->user_addr;

	strncpy(art_out->user_addr,from_addr,sizeof(art_out->user_addr));

	while((!isalnum(art_out->user_addr[0])) ||
			(strchr(art_out->user_addr,'*') != NULL) ||
			(validate_email_addr(art_out->user_addr) < 0))
	{
		d_from = dbox_new("String");
		dbox_setfield(d_from,1,art_out->user_addr);
		dbox_setfield(d_from,2,"Enter a valid From address for this message");
		dbox_show(d_from);
		if(dbox_fillin(d_from) != 0)
		{
			dbox_dispose(&d_from);
			return;
		}
		dbox_getfield(d_from,1,art_out->user_addr,sizeof(art_out->user_addr));
		dbox_dispose(&d_from);
	}


	if((t->text_length <= 1) && (art_out->supersede != 1))
	{
		/* not a Cancel message */

		if(art_out->news_mail == X_NEWS)
		{
			werr(0,"Empty message");
			return;
		}

		if(query("Do you really want to send an empty message?",NULL)==0)
			return;
	}

	/* check there are some non-quoted lines (ignore the "In-article" bit */
	/* Not implemented yet */


	dbox_getfield(d,8,save_subj,sizeof(save_subj));    /* Subject, read into temp. buf */
	save_subj_len = strlen(save_subj);

	re_prefix = memcmp(save_subj,"Re: ",4);

	if((save_subj_len == (N_SUBJECT-1))  &&    /* size of template field for Subject */
			(strlen(art_out->subject) >= N_SUBJECT) &&
			((memcmp(save_subj,art_out->subject,N_SUBJECT-1)==0) ||
			 ((re_prefix==0) && memcmp(&save_subj[4],art_out->subject,N_SUBJECT-5)==0)))
	{
		/* keep original Subject.
		   It's just been truncated in the Write Mail/News window (or with Re: prefixed) */
		art_out->keep_subject = 1;
	}
	else if((strcmp_printable(art_out->subject,save_subj)==0) ||
			((re_prefix==0) && strcmp_printable(art_out->subject,&save_subj[4])==0))
	{
		/* if art_out->subject contains non-printable control characters but is otherwise
		   identical to save_subj, then use art_out->subject */
		art_out->keep_subject = 1;
	}
	else
	{
		strcpy(art_out->subject,save_subj);   /* use new Subject */
	}

	if(art_out->news_mail == X_NEWS)
		dbox_getfield(d,9,art_out->newsgs,sizeof(art_out->newsgs));
	else
		dbox_getfield(d,9,art_out->dest,sizeof(art_out->dest));

	/* strip trailing blanks from article */
	strip_article_blanks(t);

	i = any_lower_case(art_out->subject);

	if(art_out->news_mail == X_NEWS)
	{
		/* News */
		if(i==0)
		{
			werr(0,"Bad Subject field, no letters");
			return;
		}

		if(i<2)
		{
			if(query("Bad Subject field, no lower case letters",NULL)==0)
				return;
		}

		if(memcmp_lc(art_out->subject,"cmsg ",5)==0)
		{
			werr(0,"'cmsg' not allowed in Subject field");
			return;
		}

		dbox_getfield(d,10,art_out->follow_up,sizeof(art_out->follow_up));

		dbox_getfield(d,11,art_out->dest,sizeof(art_out->newsgs));

		if(t->attachments > 0)
			msg_id_type = 8;
		else
			msg_id_type = 0;

		result=0;
		if(art_out->dest[0] != 0)
		{
			result = post_mail(t,art_out->newsgs,dont_close);
		}

		/* use different message-id for news and mail copy */
		strcpy(art_out->fname_out,get_message_id(0,msg_id_type));
		if(result==0)
		{
			result = post_news(t,dont_close);
			if(result == 0)
			{
				if(dont_close==0)
					reply_close(t);
				else
				{
					/* fade Post button until text is changed */
					wimp_set_icon_state(t->w_card,1,wimp_INOSELECT,wimp_INOSELECT);
				}
			}
			else
			{
				if(art_out->dest[0] != 0)
				{
					werr(0,"Email copy posted");
					dbox_setfield(d,11,"");   /* clear email copy field */
				}
			}

		}
	}
	else
	{
		art_out->ack = dbox_getnumeric(d,7);
		dbox_getfield(d,10,art_out->cc,sizeof(art_out->cc));
		dbox_getfield(d,11,art_out->bcc,sizeof(art_out->bcc));
		dbox_getfield(d,12,art_out->reply_to,sizeof(art_out->reply_to));
		result = post_mail(t,0,dont_close);
		if((result == 0) && (dont_close==0))
			reply_close(t);
	}


	if(result == 0)
	{
		if(dont_close)
			t->changed = 0;

		open_article(t,0x220);

		/* set status to Read and mark as Replied */
		reply_set_status(fr,cptr);
		reply_remove_draft(cptr_save,0);

		set_boxlist_extent(6);
		postedlist_reopen();
	}
}   /* end of reply_post_message */




void reply_set_ext_edit(TEXTR *t, int redraw)
/***************************************/
/* redraw  bit 0 = redraw text window
               1 = don't change t->ext_edit  */
{
	int  i;
	wimp_redrawstr r;

	if((redraw & 2) == 0)
		t->ext_edit = options.ext_edit;

	if(t->ext_edit)
	{
		i = 0;    /* show the "Editor" button */
	}
	else
	{
		i = wimp_IDELETED;
	}
	wimp_set_icon_state(t->w_card,14,i,wimp_IDELETED);  /* Edit button */
	wimp_set_icon_state(t->w_card,24,i ^ wimp_IDELETED,wimp_IDELETED);  /* Format button */

	if(redraw & 1)
	{
		/* give workarea coordinates of line to be redrawn */
		r.w = t->w_card;
		r.box.x0 = 0;
		r.box.x1 = t->workarea.box.x1;
		r.box.y0 = -500;
		r.box.y1 = 0;
		wimp_force_redraw(&r);
		r.w = t->w_text;
		memcpy(&r.box,&t->workarea.box,sizeof(r.box));
		wimp_force_redraw(&r);
	}
}   /* end of reply_ext_edit */






void reply_set_card_fields(TEXTR *t)
/**********************************/
{
	ARTICLE_OUT *art_out;
	dbox d;

	art_out = t->art_out;
	d = t->dbox_card;

	reply_set_ext_edit(t,0);
	reply_show_user_id(t);
	dbox_setfield(d,8,art_out->subject);

	if(t->text_type == X_NEWS)
	{
		if(memcmp(art_out->newsgs,"mail.",5) != 0)
			dbox_setfield(d,9,art_out->newsgs);
		else
			dbox_setfield(d,9,"");
	}
	else
	{
		dbox_setfield(d,9,art_out->dest);
		dbox_setfield(d,4,mime_style_names[t->use_mime]);

		if(art_out->no_request_ack)
			dbox_setnumeric(d,7,0);
		else
			dbox_setnumeric(d,7,t->selected_user->request_acks);
	}
}   /* end of reply_set_card_fields */







void dbox_editbut_handler(dbox d, void *handle)
/*********************************************/
{
	int field;
	FOLDREC *fr;
	TEXTR *t;
	int  shiftkey;
	ARTICLE_OUT *art_out;

	t = (TEXTR *)handle;
	art_out = t->art_out;
	fr = t->fr;

	t->fname_save[0] = 0;

	dbox_getfield(d,8,t->cardex->title,sizeof(t->cardex->title));
	dbox_getfield(d,9,t->cardex->author,sizeof(t->cardex->author));
	get_current_date_string(&t->cardex->date);

	field = dbox_get(d);
	shiftkey = akbd_pollsh() << 1;

	switch(field)
	{
	case 0:   /* signature menu */
	case 6:
		break;

	case 14: /* call external editor */
		reply_start_OLE(t);
		break;

	case 15:
		spell_load_attempt();
		spell_show(t);
		break;

	case 1:  /* post */
		reply_post_message(t);
		break;

	case 3:   /* save */
		if(dbox_persist())
			reply_save_draft(t,0);
		else
			save_text(t,0);
		break;

	case 17:    /* print */
		print_text_dialog(t,t->cardex,0);
		break;

	case 23:    /* switch between News and Mail */
		dbox_dispose(&t->dbox_card);
		t->text_type ^= 1;   /* swap news/mail */
		art_out->news_mail = t->text_type;

		text_reply_window(t,t->text_type);

		if(art_out->subject[0]==0)
			strcpy(art_out->subject,t->cardex->title);   /* not a reply */
		if(t->text_type == X_NEWS)
		{
			dbox_setfield(t->dbox_card,11,t->cardex->author);
			t->button_bar_height = NEWS_BUTTON_BAR_HEIGHT2;  /* show email_copy field */
		}
		reply_set_card_fields(t);
		set_text_extent(t);

		open_article(t,5);
		break;

	case 24:    /* format */
		text_format_text(t);
		break;

	case 13:    /* expand button window */
		t->button_bar_expanded = 0;
		if(t->text_type == X_MAIL)
		{
			if(t->button_bar_height == MAIL_BUTTON_BAR_HEIGHT)
			{
				t->button_bar_height = MAIL_BUTTON_BAR_HEIGHT2;
				t->button_bar_expanded = 1;
			}
			else
				t->button_bar_height = MAIL_BUTTON_BAR_HEIGHT;
		}
		else
		{
			if(t->button_bar_height == NEWS_BUTTON_BAR_HEIGHT)
			{
				t->button_bar_height = NEWS_BUTTON_BAR_HEIGHT2;
				t->button_bar_expanded = 1;
			}
			else
				t->button_bar_height = NEWS_BUTTON_BAR_HEIGHT;
		}
		open_article(t,2);
		break;

	default:
		if(reply_check_changed(t))
			break;

		reply_remove_draft(t->cptr_save,1);

		text_close_window(t);
		break;

	}

}   /* end of dbox_editbut_handler */





int text_record_check_changed()
/*****************************/
{
	int i;
	TEXTR *t;

	for(i=0; i<N_TEXT_DATA; i++)
	{
		if((t = text_data_record[i]) != NULL)
		{
			if(t->changed)
			{
				return(1);
			}
		}
	}
	return(0);
}   /* end of text_record_check_changed */




TEXTR *reply_data_find(int control)
/*********************************/
/* Find the record for the currently open write news/mail, if
   there is one
   control  bit 0  must only be one
            bit 1  must be mail
            bit 4  report error
*/
{
	int  i;
	TEXTR *t;
	TEXTR *result=NULL;
	char *err_msg1;

	if(control & 2)
		err_msg1 = "Write Mail";
	else
		err_msg1 = "Write Mail or News";

	for(i=0; i<N_TEXT_DATA; i++)
	{
		if(((t = text_data_record[i]) != NULL) && (t->text_type > X_VIEW2))
		{
			if((t->text_type == X_MAIL) || ((control & 2)==0))
			{
				if((control & 1) && (result != NULL))
				{
					if(control & 0x10)
						werr(0,"More than one %s window is open",err_msg1);
					return(NULL);
				}

				result = t;
			}
		}
	}
	if((result == NULL) && (control & 0x10))
	{
		werr(0,"No %s window is open",err_msg1);
	}
	return(result);
}   /* end of reply_data_find */






void text_fade_buttons(TEXTR *t)
/******************************/
{
	char *p;
	static char fade_buttons[] = {12,13,26,0};  /* fade in X-VIEW2 */

	if(t->dbox_card != NULL)
	{
		p = fade_buttons;
		while(*p != 0)
		{
			dbox_fadefield(t->dbox_card,*p++);
		}
	}
}   /* end of text_fade_buttons */




int text_exit_check()
/*******************/
{
	int  record;
	TEXTR *t;
	int  type=0;
	static char *msg_quit = "Quit";

	for(record=0; record<N_TEXT_DATA; record++)
	{
		if((t = text_data_record[record])!=NULL)
		{
			if(t->changed)
			{
				if(t->text_type > X_VIEW2)
					type |= 2;
				else
					type |= 1;
			}
		}
	}

	if(type & 2)
	{
		if(query("Unposted Write Mail/News window",msg_quit)==0)
			return(-1);
	}
	if(type & 1)
	{
		if(query("Unsaved Article Viewer with changes",msg_quit)==0)
			return(-1);
	}
	return(0);
}   /* end of text_exit_check */






void text_reply_window(TEXTR *t, int type)
/****************************************/
{
	int  colr;
	char *template_name;
	dbox d;
	wimp_wind *card_template;
	int  palette[20];

	if(type == X_MAIL)
	{
		template_name = "WriteMail";
		t->button_bar_height = MAIL_BUTTON_BAR_HEIGHT;
	}
	else
	{
		template_name = "WriteNews";
		t->button_bar_height = NEWS_BUTTON_BAR_HEIGHT;
	}

	colr = card_colours[type];

	os_swi2(0x400e5,0,(int)palette);   /* Wimp_ReadPalette */
	os_swi3r(0x40745,convert_to_palette(options.text_colrs[type-X_MAIL+10]),12,(int)palette,&colr,NULL,NULL);

	if(options.colours[3] & (1 << type-X_MAIL))
	{
		colr = 1;  /* Grey */
	}
	card_template = template_syshandle(template_name);
	card_template->colours[wimp_WCWKAREABACK] = colr;

	d = dbox_new(template_name);
	t->dbox_card = d;
	if(d != NULL)
	{
		dbox_raw_eventhandler(d,dbox_editbut_raw_handler,(void *)t);
		dbox_eventhandler(d, dbox_editbut_handler, (void *)t);
		dbox_setnumeric(d,2,0);   /* LOCK button */
		t->w_card = dbox_syshandle(d);
	}
}   /* end of text_reply_window */







void text_attach_window(TEXTR *t)
/*******************************/
{
	wimp_wind *window_template;
	template *tpl;

	tpl = template_copy(template_find("Attach"));
	window_template = &tpl->window;
	wimp_create_wind(window_template ,&t->w_attach);
	win_register_event_handler(t->w_attach,attach_window_handler,(void *)t);

}   /* attach_attach_window */





TEXTR *text_data_init(int size, int type)
/***************************************/
{
	TEXTR *t;
	int  record;
	int  i;
	wimp_wind *window_template;
	wimp_wind *card_template;
	wimp_icon *icon_ptr;
	char write_mail_tags[N_TEXT_DATA];

	memset(write_mail_tags,0,sizeof(write_mail_tags));
	record = N_TEXT_DATA;
	for(i=0; i<N_TEXT_DATA; i++)
	{
		if(text_data_record[i]==NULL)
		{
			if(record == N_TEXT_DATA)
				record = i;
		}
		else if(text_data_record[i]->text_type > X_VIEW2)
		{
			write_mail_tags[text_data_record[i]->write_mail_tag] = 1;
		}
	}
	if(record==N_TEXT_DATA)
	{
		werr(0,"No more Text windows");
		return(NULL);
	}

	t = (TEXTR *)calloc(1,sizeof(TEXTR));
	if(t==NULL)
		return(NULL);

	text_data_record[record] = t;

	size += TEXT_EXTRA;
	if(flex_alloc((flex_ptr)&t->text_base,size) == 0)
	{
		free(t);
		malloc_err(20);
		return(NULL);
	}

	t->text_buf_size = size;

	t->cardex = calloc(1,sizeof(CARD_EXPANDED));
	if(t->cardex == NULL)
	{
		if(type != X_VIEW)
			free(t);
		malloc_err(25);
		return(NULL);
	}


	t->line_tab = calloc(1,N_LINE_TAB);
	if(t->line_tab == NULL)
	{
		free(t);
		malloc_err(26);
		return(NULL);
	}
	t->n_line_tab = N_LINE_TAB;

	t->attach = NULL;
	t->num_attach = 0;

	if(type > X_VIEW2)
	{
		t->allow_edit = 1;
		t->lips_icon = 5;
		t->wordwrap = options.reply_wordwrap;

		window_template = template_syshandle("Text2");
		window_template->box.x0 = options.position_x[1];
		window_template->box.x1 = options.position_x[1] + options.position_width[1];
		window_template->box.y1 = options.position_y[1];
		if(options.restrict_height==2)
			window_template->box.y0 = options.position_y0[1];

		wimp_create_wind(window_template ,&t->w_text);
		win_register_event_handler(t->w_text,text_window_handler,(void *)t);

		text_reply_window(t,type);

		/* find a write_mail_tag */
		for(i=0; i<N_TEXT_DATA; i++)
		{
			if(write_mail_tags[i] == 0)
			{
				t->write_mail_tag = i;
				break;
			}
		}
	}
	else
	{
		t->allow_edit = 0;
		t->lips_icon = CD_LIPS;
		t->wordwrap = options.viewer_wordwrap;
		if(t->wordwrap < 20)
			t->wordwrap = 74;

		window_template = template_syshandle("Text");

		/*      if((type==X_VIEW2) || (options.reset_av_position!=0)) */
		{
			window_template->box.x0 = options.position_x[0];
			window_template->box.x1 = options.position_x[0] + options.position_width[0];
			window_template->box.y1 = options.position_y[0];
			if(options.restrict_height==2)
				window_template->box.y0 = options.position_y0[0];
		}

		wimp_create_wind(window_template,&t->w_text);
		win_register_event_handler(t->w_text,text_window_handler,(void *)t);

		if(options.article_viewer_type == 0)
			card_template = template_syshandle("Viewer");
		else
			card_template = template_syshandle("Viewer2");
		icon_ptr = (((wimp_icon*) (card_template + 1)) + CD_STATUS_SPRITE);
		t->status_sprite = icon_ptr->data.indirectsprite.spritearea = status_sprites;
		icon_ptr->data.indirectsprite.nameisname = 8;   /* length of name */


		init_dbox_card(t);

		/* set up data for article status icon */
		icon_ptr = dbox__fieldtoiconptr(t->dbox_card,CD_STATUS_SPRITE);
		t->status_sprite = icon_ptr->data.indirectsprite.name;

		/* fade buttons */
		if(type == X_VIEW2)
		{
			text_fade_buttons(t);
		}
	}
	window_template->colours[wimp_WCWKAREABACK] = text_backg_colr;

	if(t->dbox_card==NULL)
	{
		text_data_free(t);
		return(NULL);
	}
	t->w_card = dbox_syshandle(t->dbox_card);

	text_attach_window(t);
	event_attachmenumaker(t->w_text,text_menu_maker,text_menu_proc,(void *)t);


	t->sig_start = 0x7fffffff;
	t->text_type = type;
	t->filetype = 0xfff;
	t->spell_error_index = -1;
	t->use_mime = options.use_mime;

	if(type > X_VIEW2)
	{
		t->selected_user = current_user;
		t->selected_user_num = current_user_num;
		strcpy(t->selected_sig,selected_sig);
	}


	return(t);
}   /* end of text_data_init */





void reply_dbox_close()
/*********************/
{
	dbox_hide(dbox_reply);
}




void copy_url_param(char *out, char *param, int len)
/**************************************************/
{
	char *p_end;

	if(out[0] != 0)
	{
		strcat(out,", ");
		out += strlen(out);
	}

	p_end = param+len;
	while(param<p_end)
	{
		if(*param=='%')
		{
			*out = hexdig(param[1]) * 16 + hexdig(param[2]);
			param += 3;
		}
		else
		{
			*out = *param++;
		}
		if(*out != '\r')
			out++;
	}
	*out = 0;
}   /* end of copy_url_param */




void get_url_parameters(ARTICLE_OUT *art_out, char *url, char *param, char *body)
/*******************************************************************************/
{
	int  len;
	char *param_end;

	memcpy(art_out->dest,url,param-url);
	art_out->dest[param-url]=0;

	do {
		param++;
		param_end = strchr(param,'&');
		if(param_end==NULL)
			len = strlen(param);
		else
			len = param_end - param;

		if(memcmp_lc(param,"to=",3)==0)
			copy_url_param(art_out->dest,&param[3],len-3);
		else if(memcmp_lc(param,"cc=",3)==0)
			copy_url_param(art_out->cc,&param[3],len-3);
		else if(memcmp_lc(param,"subject=",8)==0)
			copy_url_param(art_out->subject,&param[8],len-8);
		else if((memcmp_lc(param,"body=",5)==0) && (body != NULL))
			copy_url_param(body,&param[5],len-5);
		else
			copy_url_param(art_out->subject,param,len);

		param = param_end;
	} while(param_end != NULL);
}   /* end of get_url_parameters */




char *cardex_addr_from_header(CARD_EXPANDED *cardex, int key)
/***********************************************************/
/* key: 12 = reply-to,  36 = return-path */
{
	int  keyword;
	int  start;
	int  arg_end;
	int  c;
	int  argument2;
	char *p = NULL;

	start = cardex->text_start;

	/* look for reply-to address */
	while((keyword = interpret_article_key(cardex->text_anchor,&start,cardex->text_length,&argument2,&arg_end)) >= 0)
	{
		if(keyword == key)
		{
			c = (*cardex->text_anchor)[arg_end];
			(*cardex->text_anchor)[arg_end] = 0;
			p = reply_extract_email_addr(*cardex->text_anchor + argument2,3);
			(*cardex->text_anchor)[arg_end] = c;
			break;
		}
	}
	return(p);
}   /* end of cardex_get_reply_to */




int reply_receipt_ack(CARD_EXPANDED *cardex, char *addr, int user, int type)
/**************************************************************************/
/* A mail message has been received with "Return-Receipt-To" line
   type=0  receipt ack
        1  subscribed to maillist
        2  unsubscribe
        3  maillist message refused
        4  fake invalid address reply
*/
{
	FILE *f;
	FILE *f2;
	FILE *f_msg;
	int  c;
	int  i;
	char *p;
	int  skip_flag;
	OPTIONS_MAILBOX *uptr;
	OPTIONS_MAILBOX *uptr1;
	ARTICLE_OUT article_out;
	char *ack_string;
	char *signon_msg;
	char *reply_to;
	char *addr1;
	char *undeliver_msg = "Send Undeliverable ack to";
	int  msg_ftype = 0;
	int  hold = 0;

	static OPTIONS_MAILBOX daemon;

	char return_addr[180];
	char fname[128];
	char fname2[128];
	char fmessage[180];

	if(cardex->status & STATUS_BIT_NEWS)
	{
		beep();
		return(0);
	}

	if(type==0)
	{
		if(options.send_mail_acks == 0)
			return(0);   /* not enabled.  Acks to mailing list control msgs are always sent */
		if(options.send_mail_acks < 3)
		{
			hold = 1;
		}
	}

	if(addr == NULL)
		return(3);

	uptr = uptr1 = &options.mailbox[user];



	if(type==4)
	{
		if(user < 0)
			user = 0;

		addr1 = cardex_addr_from_header(cardex,36);  /* Return-path: */

		if(addr1 != NULL)
		{
			strncpy0(return_addr,addr1,sizeof(return_addr));
			addr = return_addr;  /* Use Return-path rather than From */
		}

		addr1 = addr;

		reply_to = cardex_addr_from_header(cardex,12);

		if(reply_to != NULL)
		{
			sprintf(fname,"%s From: %s or the Reply-to: address?",undeliver_msg,addr);
			i = query3(fname,"From:","Reply-to:","Cancel");
			if(i==2) return(0);
		}
		else
		{
			sprintf(fname,"%s: %s ?",undeliver_msg,addr);
			i = query2(fname,"From:","Cancel");
			if(i==0) return(0);
		}

		if(i==0)
		{
			addr = reply_to;
		}
	}

	if(user < 0)
		return(1);

	check_ramfs2();   /* set tmp path */

	memset(&article_out,0,sizeof(article_out));
	strcpy(article_out.fname_out,get_message_id(0,2));    /* indicates an acknowledgement */

	if(hold)
	{
		sprintf(fname,"%sHold.Mail.%s",pluto_path,article_out.fname_out);
		sprintf(fname2,"%sHold.Envs.%s",pluto_path,article_out.fname_out);
	}
	else
	{
		sprintf(fname,"%s.%s",options.mail_out,article_out.fname_out);
		sprintf(fname2,"%s.%s",options.mail_envs,article_out.fname_out);
	}

	if(transport_opts & TOPS_MAIL_CRLF)
	{
		/* terminate lines with CR LF, write to temporary files */
		f2 = fopen_werr(fname_temp2,"w",NULL);
		if(f2==NULL) return(2);

		f = fopen_werr(fname_temp,"w",NULL);
		if(f==NULL) return(1);
	}
	else
	{
		f2 = fopen_werr(fname2,"w","Mail Envelope ");
		if(f2==NULL) return(2);

		f = fopen_werr(fname,"w","Mail Out ");
		if(f==NULL) return(1);
	}


	if((type==1) || (type==2))
	{
		/* mailing list signon or signoff */
		if(type==1)
			signon_msg = "SIGNON_MSG";
		else
			signon_msg = "SIGNOF_MSG";

		sprintf(fmessage,"%s.MailLists.%s.%s",path_choices,signon_msg,get_user_id(uptr));
		f_msg = fopen(fmessage,"r");
		msg_ftype = get_filetype(fmessage);
	}


	if(type==0)
	{
		strcpy(article_out.subject,"Delivery acknowledgement");
	}
	else if(type==4)
	{
		fprintf(f,"X-Failed-Recipients: %s\n",uptr->email_addr);
		strcpy(article_out.subject,"Mail delivery failed: returning message to sender");
		uptr1 = &daemon;
		uptr1->flags = 0x10;  /* don't include User Agent */
		strcpy(uptr1->full_name,"Mail Delivery System");
		sprintf(uptr1->email_addr,"Mailer-Daemon@%s",get_user_domain(uptr));
		uptr1->user_id_len = 13;  /* Mailer-Daemon */
	}
	else
	{
		strcpy(article_out.subject,user_full_name(uptr));
	}

	article_out.news_mail = X_MAIL;
	strcpy(article_out.dest,addr);
	strcpy(article_out.message_id,cardex->message_id);
	article_out.quoted = 1;    /* to message_id will be used */

	if(msg_ftype == FILETYPE_HTML)
	{
		fprintf(f,"Content-type: text/html\n");
	}

	strcpy(article_out.user_addr,uptr1->email_addr);
	reply_mail_header(NULL,&article_out,f,f2,uptr1);

	if(type==0)
	{
		ack_string = msgs_lookup("Y5");
		fprintf(f,ack_string, cardex->title,'\n',user_full_name(uptr),uptr->email_addr,'\n');
	}
	else if(type==4)
	{
		fprintf(f,
				"This message was created automatically by mail delivery software.\n\nA message that you sent could not be delivered to all its recipients. The\nfollowing address(es) failed:\n\n  %s\n\nThe following text was generated during the delivery attempt:\n\n------ %s ------\n\n\nThis delivery report relates to your message:\n\n\tTo: %s\n\tFrom:\t%s\n\tSubject: %s\n\nYour message could not be delivered because the local user you specified\ndoes not exist.\n\n>>>================\nspop: no such user as %s\n>>>================\n\n------ This is a copy of the message, including all the headers. ------\n\n",
				uptr->email_addr,uptr->email_addr,uptr->email_addr,addr1,cardex->title,get_user_id(uptr));

		skip_flag = 0;
		for(i=0; i<cardex->text_length; i++)
		{
			p = *cardex->text_anchor + cardex->text_start + i;
			c = *p;
			if(c == '\n')
			{
				if(skip_flag)
					skip_flag=0;

				if(memcmp_lc(p+1,"status:",7)==0)
					skip_flag = 1;
				if(memcmp_lc(p+1,"x-uidl:",7)==0)
					skip_flag = 1;
				if(memcmp_lc(p+1,"x-rcpt:",7)==0)
					skip_flag = 1;
				if(memcmp_lc(p+1,"x-envelope-to:",14)==0)
					skip_flag = 1;
				if(memcmp_lc(p+1,"envelope-to:",12)==0)
					skip_flag = 1;
			}
			if(skip_flag==0)
				fputc(c,f);
		}
	}
	else
	{
		if(((type==1) || (type==2)) && (f_msg != NULL))
		{
			/* use a custom message to reply to the SIGNON request */
			for(;;)
			{
				c = fgetc(f_msg);
				if(feof(f_msg)) break;
				fputc(c,f);
			}
			fclose(f_msg);
		}
		else
		{
			if(type==3)
				ack_string = msgs_lookup("Y7");
			else
				ack_string = msgs_lookup("Y6");
			fprintf(f,ack_string, cardex->title);
		}
	}
	fprintf(f,"\n");

	if(transport_opts & TOPS_MAIL_DOT)
	{
		fprintf(f,"\n.\n");
	}

	fclose(f);
	fclose(f2);

	if(transport_opts & TOPS_MAIL_CRLF)
	{
		if((transport_opts & TOPS_ENVS_FILES) == 0)
		{
			copy_env_file(fname_temp2,fname,2,0,2);
			copy_with_cr(fname_temp,fname,"a");
			file_delete(fname_temp2);
			file_delete(fname_temp);
		}
	}

	if(hold)
	{
		acks_held++;
	}
	if(type==0)
	{
		acks_sent++;
	}

	postedlist_reopen();
	return(0);
}   /* end of reply_receipt_ack */




/********************************************************************************/



void mbox_find_top_user()
/***********************/
{
	int  min=0x7fff;
	int  i;

	/* find user at top of users list */
	for(i=0; i<N_MAIL_BOX; i++)
	{
		if(options.mailbox[i].email_addr[0] == 0)
			continue;

		if(options.mailbox[i].position < min)
		{
			min = options.mailbox[i].position;
			current_user_num = i;
			mbox_selected = i;
		}
	}
	current_user = &options.mailbox[current_user_num];
}






void init_reply()
/***************/
{
	menu m;
	menu m_edit;
	menu m_number;

	strcpy(fname_tags,"Tags");

	memset(text_data_record,0,sizeof(text_data_record));

	dbox_reply = dbox_new("Reply");

	/* find user at top of users list */
	mbox_find_top_user();


	strcpy(selected_sig,make_legal_fname(current_user->signature));

	menu_write = menu_new("Write Message",menustr_editor);
	m_edit = menu_new("Edit",menustr_edit);
	menu_pgp = menu_new("PGP",menustr_pgp);

	m_number = menu_new("Width","012");
	menu_make_writeable(m_number,1,menu_get_number,sizeof(menu_get_number),"");
	menu_submenu(m_edit,7,m_number);


	menu_submenu(menu_write,7,m_edit);
	menu_submenu(menu_write,8,menu_pgp);

	m = menu_new("Attachments",menustr_mime_styles);
	wmenu_mime_styles = (wimp_menustr *)menu_syshandle(m);

}   /* end of init_reply */
